Merge PR #3779: Split Proposal Interface

This commit is contained in:
Joon 2019-03-15 17:47:47 +01:00 committed by Christopher Goes
parent 8d6d8adb5f
commit 465bb02d6a
19 changed files with 450 additions and 342 deletions

View File

@ -680,7 +680,7 @@ func TestDeposit(t *testing.T) {
// query proposal // query proposal
totalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))} totalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))}
proposal = getProposal(t, port, proposalID) proposal = getProposal(t, port, proposalID)
require.True(t, proposal.GetTotalDeposit().IsEqual(totalCoins)) require.True(t, proposal.TotalDeposit.IsEqual(totalCoins))
// query deposit // query deposit
deposit := getDeposit(t, port, proposalID, addr) deposit := getDeposit(t, port, proposalID, addr)
@ -718,7 +718,7 @@ func TestVote(t *testing.T) {
// query proposal // query proposal
proposal := getProposal(t, port, proposalID) proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle()) require.Equal(t, "Test", proposal.GetTitle())
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus()) require.Equal(t, gov.StatusVotingPeriod, proposal.Status)
// vote // vote
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID, "Yes", fees) resultTx = doVote(t, port, seed, name1, pw, addr, proposalID, "Yes", fees)
@ -855,13 +855,13 @@ func TestProposalsQuery(t *testing.T) {
// Only proposals #1 should be in Deposit Period // Only proposals #1 should be in Deposit Period
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod) proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
require.Len(t, proposals, 1) require.Len(t, proposals, 1)
require.Equal(t, proposalID1, proposals[0].GetProposalID()) require.Equal(t, proposalID1, proposals[0].ProposalID)
// Only proposals #2 and #3 should be in Voting Period // Only proposals #2 and #3 should be in Voting Period
proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod) proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod)
require.Len(t, proposals, 2) require.Len(t, proposals, 2)
require.Equal(t, proposalID2, proposals[0].GetProposalID()) require.Equal(t, proposalID2, proposals[0].ProposalID)
require.Equal(t, proposalID3, proposals[1].GetProposalID()) require.Equal(t, proposalID3, proposals[1].ProposalID)
// Addr1 votes on proposals #2 & #3 // Addr1 votes on proposals #2 & #3
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID2, "Yes", fees) resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID2, "Yes", fees)
@ -875,31 +875,31 @@ func TestProposalsQuery(t *testing.T) {
// Test query all proposals // Test query all proposals
proposals = getProposalsAll(t, port) proposals = getProposalsAll(t, port)
require.Equal(t, proposalID1, (proposals[0]).GetProposalID()) require.Equal(t, proposalID1, (proposals[0]).ProposalID)
require.Equal(t, proposalID2, (proposals[1]).GetProposalID()) require.Equal(t, proposalID2, (proposals[1]).ProposalID)
require.Equal(t, proposalID3, (proposals[2]).GetProposalID()) require.Equal(t, proposalID3, (proposals[2]).ProposalID)
// Test query deposited by addr1 // Test query deposited by addr1
proposals = getProposalsFilterDepositor(t, port, addrs[0]) proposals = getProposalsFilterDepositor(t, port, addrs[0])
require.Equal(t, proposalID1, (proposals[0]).GetProposalID()) require.Equal(t, proposalID1, (proposals[0]).ProposalID)
// Test query deposited by addr2 // Test query deposited by addr2
proposals = getProposalsFilterDepositor(t, port, addrs[1]) proposals = getProposalsFilterDepositor(t, port, addrs[1])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).GetProposalID()) require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted by addr1 // Test query voted by addr1
proposals = getProposalsFilterVoter(t, port, addrs[0]) proposals = getProposalsFilterVoter(t, port, addrs[0])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).GetProposalID()) require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted by addr2 // Test query voted by addr2
proposals = getProposalsFilterVoter(t, port, addrs[1]) proposals = getProposalsFilterVoter(t, port, addrs[1])
require.Equal(t, proposalID3, (proposals[0]).GetProposalID()) require.Equal(t, proposalID3, (proposals[0]).ProposalID)
// Test query voted and deposited by addr1 // Test query voted and deposited by addr1
proposals = getProposalsFilterVoterDepositor(t, port, addrs[0], addrs[0]) proposals = getProposalsFilterVoterDepositor(t, port, addrs[0], addrs[0])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) require.Equal(t, proposalID2, (proposals[0]).ProposalID)
// Test query votes on Proposal 2 // Test query votes on Proposal 2
votes := getVotes(t, port, proposalID2) votes := getVotes(t, port, proposalID2)

View File

@ -463,12 +463,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Ensure propsal is directly queryable // Ensure propsal is directly queryable
proposal1 := f.QueryGovProposal(1) proposal1 := f.QueryGovProposal(1)
require.Equal(t, uint64(1), proposal1.GetProposalID()) require.Equal(t, uint64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus()) require.Equal(t, gov.StatusDepositPeriod, proposal1.Status)
// Ensure query proposals returns properly // Ensure query proposals returns properly
proposalsQuery = f.QueryGovProposals() proposalsQuery = f.QueryGovProposals()
require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID()) require.Equal(t, uint64(1), proposalsQuery[0].ProposalID)
// Query the deposits on the proposal // Query the deposits on the proposal
deposit := f.QueryGovDeposit(1, fooAddr) deposit := f.QueryGovDeposit(1, fooAddr)
@ -507,8 +507,8 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Fetch the proposal and ensure it is now in the voting period // Fetch the proposal and ensure it is now in the voting period
proposal1 = f.QueryGovProposal(1) proposal1 = f.QueryGovProposal(1)
require.Equal(t, uint64(1), proposal1.GetProposalID()) require.Equal(t, uint64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus()) require.Equal(t, gov.StatusVotingPeriod, proposal1.Status)
// Test vote generate only // Test vote generate only
success, stdout, stderr = f.TxGovVote(1, gov.OptionYes, keyFoo, "--generate-only") success, stdout, stderr = f.TxGovVote(1, gov.OptionYes, keyFoo, "--generate-only")
@ -544,7 +544,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Ensure the proposal returns as in the voting period // Ensure the proposal returns as in the voting period
proposalsQuery = f.QueryGovProposals("--status=VotingPeriod") proposalsQuery = f.QueryGovProposals("--status=VotingPeriod")
require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID()) require.Equal(t, uint64(1), proposalsQuery[0].ProposalID)
// submit a second test proposal // submit a second test proposal
f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewCoin(denom, proposalTokens), "-y") f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewCoin(denom, proposalTokens), "-y")
@ -552,7 +552,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Test limit on proposals query // Test limit on proposals query
proposalsQuery = f.QueryGovProposals("--limit=1") proposalsQuery = f.QueryGovProposals("--limit=1")
require.Equal(t, uint64(2), proposalsQuery[0].GetProposalID()) require.Equal(t, uint64(2), proposalsQuery[0].ProposalID)
f.Cleanup() f.Cleanup()
} }

View File

@ -84,13 +84,11 @@ This type is used in a temp map when tallying
## Proposals ## Proposals
`Proposals` are an item to be voted on. `Proposals` are an item to be voted on. It contains the `ProposalContent` which denotes what this proposal is about, and the other fields, which are the mutable state of the governance process.
```go ```go
type Proposal struct { type Proposal struct {
Title string // Title of the proposal ProposalContent // Proposal content interface
Description string // Description of the proposal
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
Deposits []Deposit // List of deposits on the proposal Deposits []Deposit // List of deposits on the proposal
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
@ -108,6 +106,17 @@ type Proposal struct {
} }
``` ```
`ProposalContent`s are an interface which contains the information about the `Proposal` where it is provided from an external source, including the proposer. Governance process itself does not evaluate about the internal content.
```go
type ProposalContent interface {
GetTitle() string
GetDescription() string
ProposalType() ProposalKind
}
```
We also mention a method to update the tally for a given proposal: We also mention a method to update the tally for a given proposal:
```go ```go

View File

@ -226,7 +226,7 @@ $ gaiacli query gov votes 1
var proposal gov.Proposal var proposal gov.Proposal
cdc.MustUnmarshalJSON(res, &proposal) cdc.MustUnmarshalJSON(res, &proposal)
propStatus := proposal.GetStatus() propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params) res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params)
} else { } else {
@ -339,7 +339,7 @@ $ gaiacli query gov deposits 1
var proposal gov.Proposal var proposal gov.Proposal
cdc.MustUnmarshalJSON(res, &proposal) cdc.MustUnmarshalJSON(res, &proposal)
propStatus := proposal.GetStatus() propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params) res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params)
} else { } else {

View File

@ -266,7 +266,7 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
// For inactive proposals we must query the txs directly to get the deposits // For inactive proposals we must query the txs directly to get the deposits
// as they're no longer in state. // as they're no longer in state.
propStatus := proposal.GetStatus() propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params) res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params)
} else { } else {
@ -489,7 +489,7 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext)
// For inactive proposals we must query the txs directly to get the votes // For inactive proposals we must query the txs directly to get the votes
// as they're no longer in state. // as they're no longer in state.
propStatus := proposal.GetStatus() propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params) res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params)
} else { } else {

View File

@ -12,8 +12,9 @@ func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(MsgDeposit{}, "cosmos-sdk/MsgDeposit", nil) cdc.RegisterConcrete(MsgDeposit{}, "cosmos-sdk/MsgDeposit", nil)
cdc.RegisterConcrete(MsgVote{}, "cosmos-sdk/MsgVote", nil) cdc.RegisterConcrete(MsgVote{}, "cosmos-sdk/MsgVote", nil)
cdc.RegisterInterface((*Proposal)(nil), nil) cdc.RegisterInterface((*ProposalContent)(nil), nil)
cdc.RegisterConcrete(&TextProposal{}, "gov/TextProposal", nil) cdc.RegisterConcrete(TextProposal{}, "gov/TextProposal", nil)
cdc.RegisterConcrete(SoftwareUpgradeProposal{}, "gov/SoftwareUpgradeProposal", nil)
} }
func init() { func init() {

View File

@ -18,7 +18,10 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
var proposalID uint64 var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
inactiveProposal := keeper.GetProposal(ctx, proposalID) inactiveProposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
panic(fmt.Sprintf("proposal %d does not exist", proposalID))
}
keeper.DeleteProposal(ctx, proposalID) keeper.DeleteProposal(ctx, proposalID)
keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned) keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned)
@ -28,10 +31,10 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
logger.Info( logger.Info(
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted", fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted",
inactiveProposal.GetProposalID(), inactiveProposal.ProposalID,
inactiveProposal.GetTitle(), inactiveProposal.GetTitle(),
keeper.GetDepositParams(ctx).MinDeposit, keeper.GetDepositParams(ctx).MinDeposit,
inactiveProposal.GetTotalDeposit(), inactiveProposal.TotalDeposit,
), ),
) )
} }
@ -43,28 +46,31 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
var proposalID uint64 var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
activeProposal := keeper.GetProposal(ctx, proposalID) activeProposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
panic(fmt.Sprintf("proposal %d does not exist", proposalID))
}
passes, tallyResults := tally(ctx, keeper, activeProposal) passes, tallyResults := tally(ctx, keeper, activeProposal)
var tagValue string var tagValue string
if passes { if passes {
keeper.RefundDeposits(ctx, activeProposal.GetProposalID()) keeper.RefundDeposits(ctx, activeProposal.ProposalID)
activeProposal.SetStatus(StatusPassed) activeProposal.Status = StatusPassed
tagValue = tags.ActionProposalPassed tagValue = tags.ActionProposalPassed
} else { } else {
keeper.DeleteDeposits(ctx, activeProposal.GetProposalID()) keeper.DeleteDeposits(ctx, activeProposal.ProposalID)
activeProposal.SetStatus(StatusRejected) activeProposal.Status = StatusRejected
tagValue = tags.ActionProposalRejected tagValue = tags.ActionProposalRejected
} }
activeProposal.SetFinalTallyResult(tallyResults) activeProposal.FinalTallyResult = tallyResults
keeper.SetProposal(ctx, activeProposal) keeper.SetProposal(ctx, activeProposal)
keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.GetVotingEndTime(), activeProposal.GetProposalID()) keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.VotingEndTime, activeProposal.ProposalID)
logger.Info( logger.Info(
fmt.Sprintf( fmt.Sprintf(
"proposal %d (%s) tallied; passed: %v", "proposal %d (%s) tallied; passed: %v",
activeProposal.GetProposalID(), activeProposal.GetTitle(), passes, activeProposal.ProposalID, activeProposal.GetTitle(), passes,
), ),
) )

View File

@ -208,7 +208,9 @@ func TestTickPassedVotingPeriod(t *testing.T) {
require.True(t, activeQueue.Valid()) require.True(t, activeQueue.Valid())
var activeProposalID uint64 var activeProposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeQueue.Value(), &activeProposalID) keeper.cdc.UnmarshalBinaryLengthPrefixed(activeQueue.Value(), &activeProposalID)
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, activeProposalID).GetStatus()) proposal, ok := keeper.GetProposal(ctx, activeProposalID)
require.True(t, ok)
require.Equal(t, StatusVotingPeriod, proposal.Status)
depositsIterator := keeper.GetDeposits(ctx, proposalID) depositsIterator := keeper.GetDeposits(ctx, proposalID)
require.True(t, depositsIterator.Valid()) require.True(t, depositsIterator.Valid())
depositsIterator.Close() depositsIterator.Close()

View File

@ -122,11 +122,11 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
k.setVote(ctx, vote.ProposalID, vote.Vote.Voter, vote.Vote) k.setVote(ctx, vote.ProposalID, vote.Vote.Voter, vote.Vote)
} }
for _, proposal := range data.Proposals { for _, proposal := range data.Proposals {
switch proposal.GetStatus() { switch proposal.Status {
case StatusDepositPeriod: case StatusDepositPeriod:
k.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID()) k.InsertInactiveProposalQueue(ctx, proposal.DepositEndTime, proposal.ProposalID)
case StatusVotingPeriod: case StatusVotingPeriod:
k.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID()) k.InsertActiveProposalQueue(ctx, proposal.VotingEndTime, proposal.ProposalID)
} }
k.SetProposal(ctx, proposal) k.SetProposal(ctx, proposal)
} }
@ -142,7 +142,7 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
var votes []VoteWithMetadata var votes []VoteWithMetadata
proposals := k.GetProposalsFiltered(ctx, nil, nil, StatusNil, 0) proposals := k.GetProposalsFiltered(ctx, nil, nil, StatusNil, 0)
for _, proposal := range proposals { for _, proposal := range proposals {
proposalID := proposal.GetProposalID() proposalID := proposal.ProposalID
depositsIterator := k.GetDeposits(ctx, proposalID) depositsIterator := k.GetDeposits(ctx, proposalID)
defer depositsIterator.Close() defer depositsIterator.Close()
for ; depositsIterator.Valid(); depositsIterator.Next() { for ; depositsIterator.Valid(); depositsIterator.Next() {

View File

@ -33,9 +33,12 @@ func TestEqualProposals(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
// Create two proposals // Submit two proposals
proposal1 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal := testProposal()
proposal2 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal1, err := keeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)
proposal2, err := keeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)
// They are similar but their IDs should be different // They are similar but their IDs should be different
require.NotEqual(t, proposal1, proposal2) require.NotEqual(t, proposal1, proposal2)
@ -48,11 +51,15 @@ func TestEqualProposals(t *testing.T) {
require.False(t, state1.Equal(state2)) require.False(t, state1.Equal(state2))
// Now make proposals identical by setting both IDs to 55 // Now make proposals identical by setting both IDs to 55
proposal1.SetProposalID(55) proposal1.ProposalID = 55
proposal2.SetProposalID(55) proposal2.ProposalID = 55
require.Equal(t, proposal1, proposal1) require.Equal(t, proposal1, proposal1)
require.True(t, ProposalEqual(proposal1, proposal2)) require.True(t, ProposalEqual(proposal1, proposal2))
// Reassign proposals into state
state1.Proposals[0] = proposal1
state2.Proposals[0] = proposal2
// State should be identical now.. // State should be identical now..
require.Equal(t, state1, state2) require.Equal(t, state1, state2)
require.True(t, state1.Equal(state2)) require.True(t, state1.Equal(state2))
@ -69,17 +76,24 @@ func TestImportExportQueues(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
// Create two proposals, put the second into the voting period // Create two proposals, put the second into the voting period
proposal1 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal := testProposal()
proposalID1 := proposal1.GetProposalID() proposal1, err := keeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)
proposalID1 := proposal1.ProposalID
proposal2 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal2, err := keeper.SubmitProposal(ctx, proposal)
proposalID2 := proposal2.GetProposalID() require.NoError(t, err)
proposalID2 := proposal2.ProposalID
_, votingStarted := keeper.AddDeposit(ctx, proposalID2, addrs[0], keeper.GetDepositParams(ctx).MinDeposit) _, votingStarted := keeper.AddDeposit(ctx, proposalID2, addrs[0], keeper.GetDepositParams(ctx).MinDeposit)
require.True(t, votingStarted) require.True(t, votingStarted)
require.True(t, keeper.GetProposal(ctx, proposalID1).GetStatus() == StatusDepositPeriod) proposal1, ok := keeper.GetProposal(ctx, proposalID1)
require.True(t, keeper.GetProposal(ctx, proposalID2).GetStatus() == StatusVotingPeriod) require.True(t, ok)
proposal2, ok = keeper.GetProposal(ctx, proposalID2)
require.True(t, ok)
require.True(t, proposal1.Status == StatusDepositPeriod)
require.True(t, proposal2.Status == StatusVotingPeriod)
genAccs := mapp.AccountKeeper.GetAllAccounts(ctx) genAccs := mapp.AccountKeeper.GetAllAccounts(ctx)
@ -96,12 +110,19 @@ func TestImportExportQueues(t *testing.T) {
ctx2 = ctx2.WithBlockTime(ctx2.BlockHeader().Time.Add(keeper2.GetDepositParams(ctx2).MaxDepositPeriod).Add(keeper2.GetVotingParams(ctx2).VotingPeriod)) ctx2 = ctx2.WithBlockTime(ctx2.BlockHeader().Time.Add(keeper2.GetDepositParams(ctx2).MaxDepositPeriod).Add(keeper2.GetVotingParams(ctx2).VotingPeriod))
// Make sure that they are still in the DepositPeriod and VotingPeriod respectively // Make sure that they are still in the DepositPeriod and VotingPeriod respectively
require.True(t, keeper2.GetProposal(ctx2, proposalID1).GetStatus() == StatusDepositPeriod) proposal1, ok = keeper2.GetProposal(ctx2, proposalID1)
require.True(t, keeper2.GetProposal(ctx2, proposalID2).GetStatus() == StatusVotingPeriod) require.True(t, ok)
proposal2, ok = keeper2.GetProposal(ctx2, proposalID2)
require.True(t, ok)
require.True(t, proposal1.Status == StatusDepositPeriod)
require.True(t, proposal2.Status == StatusVotingPeriod)
// Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod. // Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod.
EndBlocker(ctx2, keeper2) EndBlocker(ctx2, keeper2)
require.Nil(t, keeper2.GetProposal(ctx2, proposalID1)) proposal1, ok = keeper2.GetProposal(ctx2, proposalID1)
require.True(t, keeper2.GetProposal(ctx2, proposalID2).GetStatus() == StatusRejected) require.False(t, ok)
proposal2, ok = keeper2.GetProposal(ctx2, proposalID2)
require.True(t, ok)
require.True(t, proposal2.Status == StatusRejected)
} }

View File

@ -25,8 +25,20 @@ func NewHandler(keeper Keeper) sdk.Handler {
} }
func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) sdk.Result { func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) sdk.Result {
proposal := keeper.NewTextProposal(ctx, msg.Title, msg.Description, msg.ProposalType) var content ProposalContent
proposalID := proposal.GetProposalID() switch msg.ProposalType {
case ProposalTypeText:
content = NewTextProposal(msg.Title, msg.Description)
case ProposalTypeSoftwareUpgrade:
content = NewSoftwareUpgradeProposal(msg.Title, msg.Description)
default:
return ErrInvalidProposalType(keeper.codespace, msg.ProposalType).Result()
}
proposal, err := keeper.SubmitProposal(ctx, content)
if err != nil {
return err.Result()
}
proposalID := proposal.ProposalID
proposalIDStr := fmt.Sprintf("%d", proposalID) proposalIDStr := fmt.Sprintf("%d", proposalID)
err, votingStarted := keeper.AddDeposit(ctx, proposalID, msg.Proposer, msg.InitialDeposit) err, votingStarted := keeper.AddDeposit(ctx, proposalID, msg.Proposer, msg.InitialDeposit)

View File

@ -95,57 +95,58 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper,
} }
// Proposals // Proposals
func (keeper Keeper) SubmitProposal(ctx sdk.Context, content ProposalContent) (proposal Proposal, err sdk.Error) {
// Creates a NewProposal
func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description string, proposalType ProposalKind) Proposal {
proposalID, err := keeper.getNewProposalID(ctx) proposalID, err := keeper.getNewProposalID(ctx)
if err != nil { if err != nil {
return nil return
} }
var proposal Proposal = &TextProposal{
ProposalID: proposalID, submitTime := ctx.BlockHeader().Time
Title: title, depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
Description: description,
ProposalType: proposalType, proposal = Proposal{
ProposalContent: content,
ProposalID: proposalID,
Status: StatusDepositPeriod, Status: StatusDepositPeriod,
FinalTallyResult: EmptyTallyResult(), FinalTallyResult: EmptyTallyResult(),
TotalDeposit: sdk.NewCoins(), TotalDeposit: sdk.NewCoins(),
SubmitTime: ctx.BlockHeader().Time, SubmitTime: submitTime,
DepositEndTime: submitTime.Add(depositPeriod),
} }
depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
proposal.SetDepositEndTime(proposal.GetSubmitTime().Add(depositPeriod))
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
keeper.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID) keeper.InsertInactiveProposalQueue(ctx, proposal.DepositEndTime, proposalID)
return proposal return
} }
// Get Proposal from store by ProposalID // Get Proposal from store by ProposalID
func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) Proposal { func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (proposal Proposal, ok bool) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyProposal(proposalID)) bz := store.Get(KeyProposal(proposalID))
if bz == nil { if bz == nil {
return nil return
} }
var proposal Proposal
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposal) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposal)
return proposal return proposal, true
} }
// Implements sdk.AccountKeeper. // Implements sdk.AccountKeeper.
func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) { func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal) bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal)
store.Set(KeyProposal(proposal.GetProposalID()), bz) store.Set(KeyProposal(proposal.ProposalID), bz)
} }
// Implements sdk.AccountKeeper. // Implements sdk.AccountKeeper.
func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) { func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
proposal := keeper.GetProposal(ctx, proposalID) proposal, ok := keeper.GetProposal(ctx, proposalID)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID) if !ok {
keeper.RemoveFromActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposalID) panic("DeleteProposal cannot fail to GetProposal")
}
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.DepositEndTime, proposalID)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.VotingEndTime, proposalID)
store.Delete(KeyProposal(proposalID)) store.Delete(KeyProposal(proposalID))
} }
@ -182,13 +183,13 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddr
} }
} }
proposal := keeper.GetProposal(ctx, proposalID) proposal, ok := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if !ok {
continue continue
} }
if validProposalStatus(status) { if validProposalStatus(status) {
if proposal.GetStatus() != status { if proposal.Status != status {
continue continue
} }
} }
@ -245,14 +246,14 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID uint64,
} }
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) { func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
proposal.SetVotingStartTime(ctx.BlockHeader().Time) proposal.VotingStartTime = ctx.BlockHeader().Time
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
proposal.SetVotingEndTime(proposal.GetVotingStartTime().Add(votingPeriod)) proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)
proposal.SetStatus(StatusVotingPeriod) proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID()) keeper.RemoveFromInactiveProposalQueue(ctx, proposal.DepositEndTime, proposal.ProposalID)
keeper.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID()) keeper.InsertActiveProposalQueue(ctx, proposal.VotingEndTime, proposal.ProposalID)
} }
// Params // Params
@ -294,11 +295,11 @@ func (keeper Keeper) setTallyParams(ctx sdk.Context, tallyParams TallyParams) {
// Adds a vote on a specific proposal // Adds a vote on a specific proposal
func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error { func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error {
proposal := keeper.GetProposal(ctx, proposalID) proposal, ok := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if !ok {
return ErrUnknownProposal(keeper.codespace, proposalID) return ErrUnknownProposal(keeper.codespace, proposalID)
} }
if proposal.GetStatus() != StatusVotingPeriod { if proposal.Status != StatusVotingPeriod {
return ErrInactiveProposal(keeper.codespace, proposalID) return ErrInactiveProposal(keeper.codespace, proposalID)
} }
@ -369,13 +370,13 @@ func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID uint64, depositorAdd
// Activates voting period when appropriate // Activates voting period when appropriate
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) { func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
// Checks to see if proposal exists // Checks to see if proposal exists
proposal := keeper.GetProposal(ctx, proposalID) proposal, ok := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if !ok {
return ErrUnknownProposal(keeper.codespace, proposalID), false return ErrUnknownProposal(keeper.codespace, proposalID), false
} }
// Check if proposal is still depositable // Check if proposal is still depositable
if (proposal.GetStatus() != StatusDepositPeriod) && (proposal.GetStatus() != StatusVotingPeriod) { if (proposal.Status != StatusDepositPeriod) && (proposal.Status != StatusVotingPeriod) {
return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false
} }
@ -387,12 +388,12 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd
} }
// Update proposal // Update proposal
proposal.SetTotalDeposit(proposal.GetTotalDeposit().Add(depositAmount)) proposal.TotalDeposit = proposal.TotalDeposit.Add(depositAmount)
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
// Check if deposit has provided sufficient total funds to transition the proposal into the voting period // Check if deposit has provided sufficient total funds to transition the proposal into the voting period
activatedVotingPeriod := false activatedVotingPeriod := false
if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) { if proposal.Status == StatusDepositPeriod && proposal.TotalDeposit.IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) {
keeper.activateVotingPeriod(ctx, proposal) keeper.activateVotingPeriod(ctx, proposal)
activatedVotingPeriod = true activatedVotingPeriod = true
} }

View File

@ -19,11 +19,14 @@ func TestGetSetProposal(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := testProposal()
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
proposalID := proposal.ProposalID
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
gotProposal := keeper.GetProposal(ctx, proposalID) gotProposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.True(t, ProposalEqual(proposal, gotProposal)) require.True(t, ProposalEqual(proposal, gotProposal))
} }
@ -35,14 +38,16 @@ func TestIncrementProposalNumber(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := testProposal()
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) keeper.SubmitProposal(ctx, tp)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) keeper.SubmitProposal(ctx, tp)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) keeper.SubmitProposal(ctx, tp)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) keeper.SubmitProposal(ctx, tp)
proposal6 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) keeper.SubmitProposal(ctx, tp)
proposal6, err := keeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
require.Equal(t, uint64(6), proposal6.GetProposalID()) require.Equal(t, uint64(6), proposal6.ProposalID)
} }
func TestActivateVotingPeriod(t *testing.T) { func TestActivateVotingPeriod(t *testing.T) {
@ -52,19 +57,25 @@ func TestActivateVotingPeriod(t *testing.T) {
mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
require.True(t, proposal.GetVotingStartTime().Equal(time.Time{})) tp := testProposal()
proposal, err := keeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
require.True(t, proposal.VotingStartTime.Equal(time.Time{}))
keeper.activateVotingPeriod(ctx, proposal) keeper.activateVotingPeriod(ctx, proposal)
require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time)) require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time))
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.GetVotingEndTime()) proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID)
require.True(t, ok)
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime)
require.True(t, activeIterator.Valid()) require.True(t, activeIterator.Valid())
var proposalID uint64 var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID()) require.Equal(t, proposalID, proposal.ProposalID)
activeIterator.Close() activeIterator.Close()
} }
@ -76,8 +87,11 @@ func TestDeposits(t *testing.T) {
mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID() tp := testProposal()
proposal, err := keeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
proposalID := proposal.ProposalID
fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(4))) fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(4)))
fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(5))) fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(5)))
@ -87,12 +101,14 @@ func TestDeposits(t *testing.T) {
expTokens := sdk.TokensFromTendermintPower(42) expTokens := sdk.TokensFromTendermintPower(42)
require.Equal(t, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, expTokens)), addr0Initial) require.Equal(t, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, expTokens)), addr0Initial)
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.NewCoins())) require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins()))
// Check no deposits at beginning // Check no deposits at beginning
deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1]) deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1])
require.False(t, found) require.False(t, found)
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{})) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.True(t, proposal.VotingStartTime.Equal(time.Time{}))
// Check first deposit // Check first deposit
err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourStake) err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourStake)
@ -102,7 +118,9 @@ func TestDeposits(t *testing.T) {
require.True(t, found) require.True(t, found)
require.Equal(t, fourStake, deposit.Amount) require.Equal(t, fourStake, deposit.Amount)
require.Equal(t, addrs[0], deposit.Depositor) require.Equal(t, addrs[0], deposit.Depositor)
require.Equal(t, fourStake, keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) proposal, ok = keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.Equal(t, fourStake, proposal.TotalDeposit)
require.Equal(t, addr0Initial.Sub(fourStake), keeper.ck.GetCoins(ctx, addrs[0])) require.Equal(t, addr0Initial.Sub(fourStake), keeper.ck.GetCoins(ctx, addrs[0]))
// Check a second deposit from same address // Check a second deposit from same address
@ -113,7 +131,9 @@ func TestDeposits(t *testing.T) {
require.True(t, found) require.True(t, found)
require.Equal(t, fourStake.Add(fiveStake), deposit.Amount) require.Equal(t, fourStake.Add(fiveStake), deposit.Amount)
require.Equal(t, addrs[0], deposit.Depositor) require.Equal(t, addrs[0], deposit.Depositor)
require.Equal(t, fourStake.Add(fiveStake), keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) proposal, ok = keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.Equal(t, fourStake.Add(fiveStake), proposal.TotalDeposit)
require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), keeper.ck.GetCoins(ctx, addrs[0])) require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), keeper.ck.GetCoins(ctx, addrs[0]))
// Check third deposit from a new address // Check third deposit from a new address
@ -124,11 +144,15 @@ func TestDeposits(t *testing.T) {
require.True(t, found) require.True(t, found)
require.Equal(t, addrs[1], deposit.Depositor) require.Equal(t, addrs[1], deposit.Depositor)
require.Equal(t, fourStake, deposit.Amount) require.Equal(t, fourStake, deposit.Amount)
require.Equal(t, fourStake.Add(fiveStake).Add(fourStake), keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) proposal, ok = keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.Equal(t, fourStake.Add(fiveStake).Add(fourStake), proposal.TotalDeposit)
require.Equal(t, addr1Initial.Sub(fourStake), keeper.ck.GetCoins(ctx, addrs[1])) require.Equal(t, addr1Initial.Sub(fourStake), keeper.ck.GetCoins(ctx, addrs[1]))
// Check that proposal moved to voting period // Check that proposal moved to voting period
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time)) proposal, ok = keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time))
// Test deposit iterator // Test deposit iterator
depositsIterator := keeper.GetDeposits(ctx, proposalID) depositsIterator := keeper.GetDeposits(ctx, proposalID)
@ -164,10 +188,13 @@ func TestVotes(t *testing.T) {
mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
proposal.SetStatus(StatusVotingPeriod) tp := testProposal()
proposal, err := keeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
// Test first vote // Test first vote
@ -224,20 +251,25 @@ func TestProposalQueues(t *testing.T) {
mapp.InitChainer(ctx, abci.RequestInitChain{}) mapp.InitChainer(ctx, abci.RequestInitChain{})
// create test proposals // create test proposals
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := testProposal()
proposal, err := keeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.GetDepositEndTime()) inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime)
require.True(t, inactiveIterator.Valid()) require.True(t, inactiveIterator.Valid())
var proposalID uint64 var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID) keeper.cdc.UnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID()) require.Equal(t, proposalID, proposal.ProposalID)
inactiveIterator.Close() inactiveIterator.Close()
keeper.activateVotingPeriod(ctx, proposal) keeper.activateVotingPeriod(ctx, proposal)
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.GetVotingEndTime()) proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID)
require.True(t, ok)
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime)
require.True(t, activeIterator.Valid()) require.True(t, activeIterator.Valid())
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID()) require.Equal(t, proposalID, proposal.ProposalID)
activeIterator.Close() activeIterator.Close()
} }

View File

@ -9,81 +9,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
// Proposal interface // Proposal is a struct used by gov module internally
type Proposal interface { // embedds ProposalContent with additional fields to record the status of the proposal process
GetProposalID() uint64 type Proposal struct {
SetProposalID(uint64) ProposalContent `json:"proposal_content"` // Proposal content interface
GetTitle() string ProposalID uint64 `json:"proposal_id"` // ID of the proposal
SetTitle(string)
GetDescription() string
SetDescription(string)
GetProposalType() ProposalKind
SetProposalType(ProposalKind)
GetStatus() ProposalStatus
SetStatus(ProposalStatus)
GetFinalTallyResult() TallyResult
SetFinalTallyResult(TallyResult)
GetSubmitTime() time.Time
SetSubmitTime(time.Time)
GetDepositEndTime() time.Time
SetDepositEndTime(time.Time)
GetTotalDeposit() sdk.Coins
SetTotalDeposit(sdk.Coins)
GetVotingStartTime() time.Time
SetVotingStartTime(time.Time)
GetVotingEndTime() time.Time
SetVotingEndTime(time.Time)
String() string
}
// Proposals is an array of proposal
type Proposals []Proposal
func (p Proposals) String() string {
out := "ID - (Status) [Type] Title\n"
for _, prop := range p {
out += fmt.Sprintf("%d - (%s) [%s] %s\n",
prop.GetProposalID(), prop.GetStatus(),
prop.GetProposalType(), prop.GetTitle())
}
return strings.TrimSpace(out)
}
// 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.GetFinalTallyResult().Equals(proposalB.GetFinalTallyResult()) &&
proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) &&
proposalA.GetDepositEndTime().Equal(proposalB.GetDepositEndTime()) &&
proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) &&
proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) &&
proposalA.GetVotingEndTime().Equal(proposalB.GetVotingEndTime()) {
return true
}
return false
}
// Text Proposals
type TextProposal struct {
ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Title string `json:"title"` // Title of the proposal
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}
FinalTallyResult TallyResult `json:"final_tally_result"` // Result of Tallys FinalTallyResult TallyResult `json:"final_tally_result"` // Result of Tallys
@ -96,55 +27,83 @@ type TextProposal struct {
VotingEndTime time.Time `json:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied VotingEndTime time.Time `json:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied
} }
// Implements Proposal Interface // nolint
var _ Proposal = (*TextProposal)(nil) func (p Proposal) String() string {
return fmt.Sprintf(`Proposal %d:
Title: %s
Type: %s
Status: %s
Submit Time: %s
Deposit End Time: %s
Total Deposit: %s
Voting Start Time: %s
Voting End Time: %s`, p.ProposalID, p.GetTitle(), p.ProposalType(),
p.Status, p.SubmitTime, p.DepositEndTime,
p.TotalDeposit, p.VotingStartTime, p.VotingEndTime)
}
// ProposalContent is an interface that has title, description, and proposaltype
// that the governance module can use to identify them and generate human readable messages
// ProposalContent can have additional fields, which will handled by ProposalHandlers
// via type assertion, e.g. parameter change amount in ParameterChangeProposal
type ProposalContent interface {
GetTitle() string
GetDescription() string
ProposalType() ProposalKind
}
// Proposals is an array of proposal
type Proposals []Proposal
// nolint // nolint
func (tp TextProposal) GetProposalID() uint64 { return tp.ProposalID } func (p Proposals) String() string {
func (tp *TextProposal) SetProposalID(proposalID uint64) { tp.ProposalID = proposalID } out := "ID - (Status) [Type] Title\n"
func (tp TextProposal) GetTitle() string { return tp.Title } for _, prop := range p {
func (tp *TextProposal) SetTitle(title string) { tp.Title = title } out += fmt.Sprintf("%d - (%s) [%s] %s\n",
func (tp TextProposal) GetDescription() string { return tp.Description } prop.ProposalID, prop.Status,
func (tp *TextProposal) SetDescription(description string) { tp.Description = description } prop.ProposalType(), prop.GetTitle())
func (tp TextProposal) GetProposalType() ProposalKind { return tp.ProposalType } }
func (tp *TextProposal) SetProposalType(proposalType ProposalKind) { tp.ProposalType = proposalType } return strings.TrimSpace(out)
func (tp TextProposal) GetStatus() ProposalStatus { return tp.Status }
func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status }
func (tp TextProposal) GetFinalTallyResult() TallyResult { return tp.FinalTallyResult }
func (tp *TextProposal) SetFinalTallyResult(tallyResult TallyResult) {
tp.FinalTallyResult = tallyResult
}
func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime }
func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime }
func (tp TextProposal) GetDepositEndTime() time.Time { return tp.DepositEndTime }
func (tp *TextProposal) SetDepositEndTime(depositEndTime time.Time) {
tp.DepositEndTime = depositEndTime
}
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit }
func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime }
func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) {
tp.VotingStartTime = votingStartTime
}
func (tp TextProposal) GetVotingEndTime() time.Time { return tp.VotingEndTime }
func (tp *TextProposal) SetVotingEndTime(votingEndTime time.Time) {
tp.VotingEndTime = votingEndTime
} }
func (tp TextProposal) String() string { // Text Proposals
return fmt.Sprintf(`Proposal %d: type TextProposal struct {
Title: %s Title string `json:"title"` // Title of the proposal
Type: %s Description string `json:"description"` // Description of the proposal
Status: %s
Submit Time: %s
Deposit End Time: %s
Total Deposit: %s
Voting Start Time: %s
Voting End Time: %s`, tp.ProposalID, tp.Title, tp.ProposalType,
tp.Status, tp.SubmitTime, tp.DepositEndTime,
tp.TotalDeposit, tp.VotingStartTime, tp.VotingEndTime)
} }
func NewTextProposal(title, description string) TextProposal {
return TextProposal{
Title: title,
Description: description,
}
}
// Implements Proposal Interface
var _ ProposalContent = TextProposal{}
// nolint
func (tp TextProposal) GetTitle() string { return tp.Title }
func (tp TextProposal) GetDescription() string { return tp.Description }
func (tp TextProposal) ProposalType() ProposalKind { return ProposalTypeText }
// Software Upgrade Proposals
type SoftwareUpgradeProposal struct {
TextProposal
}
func NewSoftwareUpgradeProposal(title, description string) SoftwareUpgradeProposal {
return SoftwareUpgradeProposal{
TextProposal: NewTextProposal(title, description),
}
}
// Implements Proposal Interface
var _ ProposalContent = SoftwareUpgradeProposal{}
// nolint
func (sup SoftwareUpgradeProposal) ProposalType() ProposalKind { return ProposalTypeSoftwareUpgrade }
// ProposalQueue // ProposalQueue
type ProposalQueue []uint64 type ProposalQueue []uint64

View File

@ -99,8 +99,8 @@ func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error()))
} }
proposal := keeper.GetProposal(ctx, params.ProposalID) proposal, ok := keeper.GetProposal(ctx, params.ProposalID)
if proposal == nil { if !ok {
return nil, ErrUnknownProposal(DefaultCodespace, params.ProposalID) return nil, ErrUnknownProposal(DefaultCodespace, params.ProposalID)
} }
@ -205,17 +205,17 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke
proposalID := params.ProposalID proposalID := params.ProposalID
proposal := keeper.GetProposal(ctx, proposalID) proposal, ok := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if !ok {
return nil, ErrUnknownProposal(DefaultCodespace, proposalID) return nil, ErrUnknownProposal(DefaultCodespace, proposalID)
} }
var tallyResult TallyResult var tallyResult TallyResult
if proposal.GetStatus() == StatusDepositPeriod { if proposal.Status == StatusDepositPeriod {
tallyResult = EmptyTallyResult() tallyResult = EmptyTallyResult()
} else if proposal.GetStatus() == StatusPassed || proposal.GetStatus() == StatusRejected { } else if proposal.Status == StatusPassed || proposal.Status == StatusRejected {
tallyResult = proposal.GetFinalTallyResult() tallyResult = proposal.FinalTallyResult
} else { } else {
// proposal is in voting period // proposal is in voting period
_, tallyResult = tally(ctx, keeper, proposal) _, tallyResult = tally(ctx, keeper, proposal)

View File

@ -227,12 +227,12 @@ func testQueries(t *testing.T) {
// Only proposal #1 should be in Deposit Period // Only proposal #1 should be in Deposit Period
proposals := getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusDepositPeriod, 0) proposals := getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusDepositPeriod, 0)
require.Len(t, proposals, 1) require.Len(t, proposals, 1)
require.Equal(t, proposalID1, proposals[0].GetProposalID()) require.Equal(t, proposalID1, proposals[0].ProposalID)
// Only proposals #2 and #3 should be in Voting Period // Only proposals #2 and #3 should be in Voting Period
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusVotingPeriod, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusVotingPeriod, 0)
require.Len(t, proposals, 2) require.Len(t, proposals, 2)
require.Equal(t, proposalID2, proposals[0].GetProposalID()) require.Equal(t, proposalID2, proposals[0].ProposalID)
require.Equal(t, proposalID3, proposals[1].GetProposalID()) require.Equal(t, proposalID3, proposals[1].ProposalID)
// Addrs[0] votes on proposals #2 & #3 // Addrs[0] votes on proposals #2 & #3
handler(ctx, NewMsgVote(addrs[0], proposalID2, OptionYes)) handler(ctx, NewMsgVote(addrs[0], proposalID2, OptionYes))
@ -243,8 +243,8 @@ func testQueries(t *testing.T) {
// Test query voted by addrs[0] // Test query voted by addrs[0]
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, addrs[0], StatusNil, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, nil, addrs[0], StatusNil, 0)
require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).GetProposalID()) require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query votes on Proposal 2 // Test query votes on Proposal 2
votes := getQueriedVotes(t, ctx, cdc, querier, proposalID2) votes := getQueriedVotes(t, ctx, cdc, querier, proposalID2)
@ -263,26 +263,26 @@ func testQueries(t *testing.T) {
// Test query all proposals // Test query all proposals
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusNil, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusNil, 0)
require.Equal(t, proposalID1, (proposals[0]).GetProposalID()) require.Equal(t, proposalID1, (proposals[0]).ProposalID)
require.Equal(t, proposalID2, (proposals[1]).GetProposalID()) require.Equal(t, proposalID2, (proposals[1]).ProposalID)
require.Equal(t, proposalID3, (proposals[2]).GetProposalID()) require.Equal(t, proposalID3, (proposals[2]).ProposalID)
// Test query voted by addrs[1] // Test query voted by addrs[1]
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, addrs[1], StatusNil, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, nil, addrs[1], StatusNil, 0)
require.Equal(t, proposalID3, (proposals[0]).GetProposalID()) require.Equal(t, proposalID3, (proposals[0]).ProposalID)
// Test query deposited by addrs[0] // Test query deposited by addrs[0]
proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[0], nil, StatusNil, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[0], nil, StatusNil, 0)
require.Equal(t, proposalID1, (proposals[0]).GetProposalID()) require.Equal(t, proposalID1, (proposals[0]).ProposalID)
// Test query deposited by addr2 // Test query deposited by addr2
proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[1], nil, StatusNil, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[1], nil, StatusNil, 0)
require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).GetProposalID()) require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted AND deposited by addr1 // Test query voted AND deposited by addr1
proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[0], addrs[0], StatusNil, 0) proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[0], addrs[0], StatusNil, 0)
require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) require.Equal(t, proposalID2, (proposals[0]).ProposalID)
// Test Tally Query // Test Tally Query
tally := getQueriedTally(t, ctx, cdc, querier, proposalID2) tally := getQueriedTally(t, ctx, cdc, querier, proposalID2)

View File

@ -49,7 +49,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
}) })
// iterate over all the votes // iterate over all the votes
votesIterator := keeper.GetVotes(ctx, proposal.GetProposalID()) votesIterator := keeper.GetVotes(ctx, proposal.ProposalID)
defer votesIterator.Close() defer votesIterator.Close()
for ; votesIterator.Valid(); votesIterator.Next() { for ; votesIterator.Valid(); votesIterator.Next() {
vote := &Vote{} vote := &Vote{}

View File

@ -53,12 +53,16 @@ func TestTallyNoOneVotes(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.True(t, tallyResults.Equals(EmptyTallyResult())) require.True(t, tallyResults.Equals(EmptyTallyResult()))
@ -81,15 +85,19 @@ func TestTallyNoQuorum(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{2, 5}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{2, 5})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, _ := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
} }
@ -110,17 +118,21 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.True(t, passes) require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -143,17 +155,21 @@ func TestTallyOnlyValidators51No(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 6}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 6})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, _ := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
} }
@ -175,19 +191,23 @@ func TestTallyOnlyValidators51Yes(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.True(t, passes) require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -210,19 +230,23 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNoWithVeto) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNoWithVeto)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -245,19 +269,23 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.True(t, passes) require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -280,19 +308,23 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -315,17 +347,21 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7}) createValidators(t, stakingHandler, ctx, valAddrs, []int64{6, 6, 7})
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -352,12 +388,14 @@ func TestTallyDelgatorOverride(t *testing.T) {
delegator1Msg := staking.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewCoin(sdk.DefaultBondDenom, delTokens)) delegator1Msg := staking.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewCoin(sdk.DefaultBondDenom, delTokens))
stakingHandler(ctx, delegator1Msg) stakingHandler(ctx, delegator1Msg)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
@ -366,7 +404,9 @@ func TestTallyDelgatorOverride(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -393,19 +433,23 @@ func TestTallyDelgatorInherit(t *testing.T) {
delegator1Msg := staking.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewCoin(sdk.DefaultBondDenom, delTokens)) delegator1Msg := staking.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewCoin(sdk.DefaultBondDenom, delTokens))
stakingHandler(ctx, delegator1Msg) stakingHandler(ctx, delegator1Msg)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionNo)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.True(t, passes) require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -434,12 +478,14 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
delegator1Msg2 := staking.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewCoin(sdk.DefaultBondDenom, delTokens)) delegator1Msg2 := staking.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewCoin(sdk.DefaultBondDenom, delTokens))
stakingHandler(ctx, delegator1Msg2) stakingHandler(ctx, delegator1Msg2)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err) require.Nil(t, err)
@ -448,7 +494,9 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -490,19 +538,23 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) {
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.False(t, passes) require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))
@ -538,19 +590,23 @@ func TestTallyJailedValidator(t *testing.T) {
staking.EndBlocker(ctx, sk) staking.EndBlocker(ctx, sk)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) tp := TextProposal{"Test", "description"}
proposalID := proposal.GetProposalID() proposal, err := keeper.SubmitProposal(ctx, tp)
proposal.SetStatus(StatusVotingPeriod) require.NoError(t, err)
proposalID := proposal.ProposalID
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) err = keeper.AddVote(ctx, proposalID, addrs[0], OptionYes)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo)
require.Nil(t, err) require.Nil(t, err)
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err) require.Nil(t, err)
passes, tallyResults := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) proposal, ok := keeper.GetProposal(ctx, proposalID)
require.True(t, ok)
passes, tallyResults := tally(ctx, keeper, proposal)
require.True(t, passes) require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult())) require.False(t, tallyResults.Equals(EmptyTallyResult()))

View File

@ -146,3 +146,12 @@ func SortByteArrays(src [][]byte) [][]byte {
sort.Sort(sorted) sort.Sort(sorted)
return sorted return sorted
} }
func testProposal() TextProposal {
return NewTextProposal("Test", "description")
}
// checks if two proposals are equal (note: slow, for tests only)
func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
return bytes.Equal(msgCdc.MustMarshalBinaryBare(proposalA), msgCdc.MustMarshalBinaryBare(proposalB))
}