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
totalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))}
proposal = getProposal(t, port, proposalID)
require.True(t, proposal.GetTotalDeposit().IsEqual(totalCoins))
require.True(t, proposal.TotalDeposit.IsEqual(totalCoins))
// query deposit
deposit := getDeposit(t, port, proposalID, addr)
@ -718,7 +718,7 @@ func TestVote(t *testing.T) {
// query proposal
proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle())
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
require.Equal(t, gov.StatusVotingPeriod, proposal.Status)
// vote
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
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
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
proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod)
require.Len(t, proposals, 2)
require.Equal(t, proposalID2, proposals[0].GetProposalID())
require.Equal(t, proposalID3, proposals[1].GetProposalID())
require.Equal(t, proposalID2, proposals[0].ProposalID)
require.Equal(t, proposalID3, proposals[1].ProposalID)
// Addr1 votes on proposals #2 & #3
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
proposals = getProposalsAll(t, port)
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
require.Equal(t, proposalID2, (proposals[1]).GetProposalID())
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
require.Equal(t, proposalID2, (proposals[1]).ProposalID)
require.Equal(t, proposalID3, (proposals[2]).ProposalID)
// Test query deposited by addr1
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
proposals = getProposalsFilterDepositor(t, port, addrs[1])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted by addr1
proposals = getProposalsFilterVoter(t, port, addrs[0])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted by addr2
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
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
votes := getVotes(t, port, proposalID2)

View File

@ -463,12 +463,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Ensure propsal is directly queryable
proposal1 := f.QueryGovProposal(1)
require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
require.Equal(t, uint64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusDepositPeriod, proposal1.Status)
// Ensure query proposals returns properly
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
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
proposal1 = f.QueryGovProposal(1)
require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
require.Equal(t, uint64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusVotingPeriod, proposal1.Status)
// Test vote 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
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
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
proposalsQuery = f.QueryGovProposals("--limit=1")
require.Equal(t, uint64(2), proposalsQuery[0].GetProposalID())
require.Equal(t, uint64(2), proposalsQuery[0].ProposalID)
f.Cleanup()
}

View File

@ -84,13 +84,11 @@ This type is used in a temp map when tallying
## 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
type Proposal struct {
Title string // Title of the proposal
Description string // Description of the proposal
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
ProposalContent // Proposal content interface
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
Deposits []Deposit // List of deposits on the proposal
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:
```go

View File

@ -226,7 +226,7 @@ $ gaiacli query gov votes 1
var proposal gov.Proposal
cdc.MustUnmarshalJSON(res, &proposal)
propStatus := proposal.GetStatus()
propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params)
} else {
@ -339,7 +339,7 @@ $ gaiacli query gov deposits 1
var proposal gov.Proposal
cdc.MustUnmarshalJSON(res, &proposal)
propStatus := proposal.GetStatus()
propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params)
} 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
// as they're no longer in state.
propStatus := proposal.GetStatus()
propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params)
} 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
// as they're no longer in state.
propStatus := proposal.GetStatus()
propStatus := proposal.Status
if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) {
res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params)
} else {

View File

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

View File

@ -18,7 +18,10 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
var proposalID uint64
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.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned)
@ -28,10 +31,10 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
logger.Info(
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted",
inactiveProposal.GetProposalID(),
inactiveProposal.ProposalID,
inactiveProposal.GetTitle(),
keeper.GetDepositParams(ctx).MinDeposit,
inactiveProposal.GetTotalDeposit(),
inactiveProposal.TotalDeposit,
),
)
}
@ -43,28 +46,31 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
var proposalID uint64
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)
var tagValue string
if passes {
keeper.RefundDeposits(ctx, activeProposal.GetProposalID())
activeProposal.SetStatus(StatusPassed)
keeper.RefundDeposits(ctx, activeProposal.ProposalID)
activeProposal.Status = StatusPassed
tagValue = tags.ActionProposalPassed
} else {
keeper.DeleteDeposits(ctx, activeProposal.GetProposalID())
activeProposal.SetStatus(StatusRejected)
keeper.DeleteDeposits(ctx, activeProposal.ProposalID)
activeProposal.Status = StatusRejected
tagValue = tags.ActionProposalRejected
}
activeProposal.SetFinalTallyResult(tallyResults)
activeProposal.FinalTallyResult = tallyResults
keeper.SetProposal(ctx, activeProposal)
keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.GetVotingEndTime(), activeProposal.GetProposalID())
keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.VotingEndTime, activeProposal.ProposalID)
logger.Info(
fmt.Sprintf(
"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())
var activeProposalID uint64
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)
require.True(t, depositsIterator.Valid())
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)
}
for _, proposal := range data.Proposals {
switch proposal.GetStatus() {
switch proposal.Status {
case StatusDepositPeriod:
k.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID())
k.InsertInactiveProposalQueue(ctx, proposal.DepositEndTime, proposal.ProposalID)
case StatusVotingPeriod:
k.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID())
k.InsertActiveProposalQueue(ctx, proposal.VotingEndTime, proposal.ProposalID)
}
k.SetProposal(ctx, proposal)
}
@ -142,7 +142,7 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
var votes []VoteWithMetadata
proposals := k.GetProposalsFiltered(ctx, nil, nil, StatusNil, 0)
for _, proposal := range proposals {
proposalID := proposal.GetProposalID()
proposalID := proposal.ProposalID
depositsIterator := k.GetDeposits(ctx, proposalID)
defer depositsIterator.Close()
for ; depositsIterator.Valid(); depositsIterator.Next() {

View File

@ -33,9 +33,12 @@ func TestEqualProposals(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
// Create two proposals
proposal1 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposal2 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
// Submit two proposals
proposal := testProposal()
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
require.NotEqual(t, proposal1, proposal2)
@ -48,11 +51,15 @@ func TestEqualProposals(t *testing.T) {
require.False(t, state1.Equal(state2))
// Now make proposals identical by setting both IDs to 55
proposal1.SetProposalID(55)
proposal2.SetProposalID(55)
proposal1.ProposalID = 55
proposal2.ProposalID = 55
require.Equal(t, proposal1, proposal1)
require.True(t, ProposalEqual(proposal1, proposal2))
// Reassign proposals into state
state1.Proposals[0] = proposal1
state2.Proposals[0] = proposal2
// State should be identical now..
require.Equal(t, state1, state2)
require.True(t, state1.Equal(state2))
@ -69,17 +76,24 @@ func TestImportExportQueues(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
// Create two proposals, put the second into the voting period
proposal1 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID1 := proposal1.GetProposalID()
proposal := testProposal()
proposal1, err := keeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)
proposalID1 := proposal1.ProposalID
proposal2 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID2 := proposal2.GetProposalID()
proposal2, err := keeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)
proposalID2 := proposal2.ProposalID
_, votingStarted := keeper.AddDeposit(ctx, proposalID2, addrs[0], keeper.GetDepositParams(ctx).MinDeposit)
require.True(t, votingStarted)
require.True(t, keeper.GetProposal(ctx, proposalID1).GetStatus() == StatusDepositPeriod)
require.True(t, keeper.GetProposal(ctx, proposalID2).GetStatus() == StatusVotingPeriod)
proposal1, ok := keeper.GetProposal(ctx, proposalID1)
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)
@ -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))
// Make sure that they are still in the DepositPeriod and VotingPeriod respectively
require.True(t, keeper2.GetProposal(ctx2, proposalID1).GetStatus() == StatusDepositPeriod)
require.True(t, keeper2.GetProposal(ctx2, proposalID2).GetStatus() == StatusVotingPeriod)
proposal1, ok = keeper2.GetProposal(ctx2, proposalID1)
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.
EndBlocker(ctx2, keeper2)
require.Nil(t, keeper2.GetProposal(ctx2, proposalID1))
require.True(t, keeper2.GetProposal(ctx2, proposalID2).GetStatus() == StatusRejected)
proposal1, ok = keeper2.GetProposal(ctx2, proposalID1)
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 {
proposal := keeper.NewTextProposal(ctx, msg.Title, msg.Description, msg.ProposalType)
proposalID := proposal.GetProposalID()
var content ProposalContent
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)
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
// Creates a NewProposal
func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description string, proposalType ProposalKind) Proposal {
func (keeper Keeper) SubmitProposal(ctx sdk.Context, content ProposalContent) (proposal Proposal, err sdk.Error) {
proposalID, err := keeper.getNewProposalID(ctx)
if err != nil {
return nil
return
}
var proposal Proposal = &TextProposal{
ProposalID: proposalID,
Title: title,
Description: description,
ProposalType: proposalType,
submitTime := ctx.BlockHeader().Time
depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
proposal = Proposal{
ProposalContent: content,
ProposalID: proposalID,
Status: StatusDepositPeriod,
FinalTallyResult: EmptyTallyResult(),
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.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
return proposal
keeper.InsertInactiveProposalQueue(ctx, proposal.DepositEndTime, proposalID)
return
}
// 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)
bz := store.Get(KeyProposal(proposalID))
if bz == nil {
return nil
return
}
var proposal Proposal
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposal)
return proposal
return proposal, true
}
// Implements sdk.AccountKeeper.
func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) {
store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal)
store.Set(KeyProposal(proposal.GetProposalID()), bz)
store.Set(KeyProposal(proposal.ProposalID), bz)
}
// Implements sdk.AccountKeeper.
func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
proposal := keeper.GetProposal(ctx, proposalID)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposalID)
proposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
panic("DeleteProposal cannot fail to GetProposal")
}
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.DepositEndTime, proposalID)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.VotingEndTime, proposalID)
store.Delete(KeyProposal(proposalID))
}
@ -182,13 +183,13 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddr
}
}
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
proposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
continue
}
if validProposalStatus(status) {
if proposal.GetStatus() != status {
if proposal.Status != status {
continue
}
}
@ -245,14 +246,14 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID uint64,
}
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
proposal.SetVotingStartTime(ctx.BlockHeader().Time)
proposal.VotingStartTime = ctx.BlockHeader().Time
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
proposal.SetVotingEndTime(proposal.GetVotingStartTime().Add(votingPeriod))
proposal.SetStatus(StatusVotingPeriod)
proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)
proposal.Status = StatusVotingPeriod
keeper.SetProposal(ctx, proposal)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID())
keeper.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID())
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.DepositEndTime, proposal.ProposalID)
keeper.InsertActiveProposalQueue(ctx, proposal.VotingEndTime, proposal.ProposalID)
}
// Params
@ -294,11 +295,11 @@ func (keeper Keeper) setTallyParams(ctx sdk.Context, tallyParams TallyParams) {
// Adds a vote on a specific proposal
func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error {
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
proposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
return ErrUnknownProposal(keeper.codespace, proposalID)
}
if proposal.GetStatus() != StatusVotingPeriod {
if proposal.Status != StatusVotingPeriod {
return ErrInactiveProposal(keeper.codespace, proposalID)
}
@ -369,13 +370,13 @@ func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID uint64, depositorAdd
// Activates voting period when appropriate
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
// Checks to see if proposal exists
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
proposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
return ErrUnknownProposal(keeper.codespace, proposalID), false
}
// 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
}
@ -387,12 +388,12 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd
}
// Update proposal
proposal.SetTotalDeposit(proposal.GetTotalDeposit().Add(depositAmount))
proposal.TotalDeposit = proposal.TotalDeposit.Add(depositAmount)
keeper.SetProposal(ctx, proposal)
// Check if deposit has provided sufficient total funds to transition the proposal into the voting period
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)
activatedVotingPeriod = true
}

View File

@ -19,11 +19,14 @@ func TestGetSetProposal(t *testing.T) {
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
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))
}
@ -35,14 +38,16 @@ func TestIncrementProposalNumber(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposal6 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
tp := testProposal()
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
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) {
@ -52,19 +57,25 @@ func TestActivateVotingPeriod(t *testing.T) {
mapp.BeginBlock(abci.RequestBeginBlock{Header: 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)
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())
var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
require.Equal(t, proposalID, proposal.ProposalID)
activeIterator.Close()
}
@ -76,8 +87,11 @@ func TestDeposits(t *testing.T) {
mapp.BeginBlock(abci.RequestBeginBlock{Header: 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)))
fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(5)))
@ -87,12 +101,14 @@ func TestDeposits(t *testing.T) {
expTokens := sdk.TokensFromTendermintPower(42)
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
deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1])
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
err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourStake)
@ -102,7 +118,9 @@ func TestDeposits(t *testing.T) {
require.True(t, found)
require.Equal(t, fourStake, deposit.Amount)
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]))
// Check a second deposit from same address
@ -113,7 +131,9 @@ func TestDeposits(t *testing.T) {
require.True(t, found)
require.Equal(t, fourStake.Add(fiveStake), deposit.Amount)
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]))
// Check third deposit from a new address
@ -124,11 +144,15 @@ func TestDeposits(t *testing.T) {
require.True(t, found)
require.Equal(t, addrs[1], deposit.Depositor)
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]))
// 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
depositsIterator := keeper.GetDeposits(ctx, proposalID)
@ -164,10 +188,13 @@ func TestVotes(t *testing.T) {
mapp.BeginBlock(abci.RequestBeginBlock{Header: 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)
// Test first vote
@ -224,20 +251,25 @@ func TestProposalQueues(t *testing.T) {
mapp.InitChainer(ctx, abci.RequestInitChain{})
// 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())
var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
require.Equal(t, proposalID, proposal.ProposalID)
inactiveIterator.Close()
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())
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
require.Equal(t, proposalID, proposal.ProposalID)
activeIterator.Close()
}

View File

@ -9,81 +9,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Proposal interface
type Proposal interface {
GetProposalID() uint64
SetProposalID(uint64)
// Proposal is a struct used by gov module internally
// embedds ProposalContent with additional fields to record the status of the proposal process
type Proposal struct {
ProposalContent `json:"proposal_content"` // Proposal content interface
GetTitle() string
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}
ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
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
}
// Implements Proposal Interface
var _ Proposal = (*TextProposal)(nil)
// nolint
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
func (tp TextProposal) GetProposalID() uint64 { return tp.ProposalID }
func (tp *TextProposal) SetProposalID(proposalID uint64) { tp.ProposalID = proposalID }
func (tp TextProposal) GetTitle() string { return tp.Title }
func (tp *TextProposal) SetTitle(title string) { tp.Title = title }
func (tp TextProposal) GetDescription() string { return tp.Description }
func (tp *TextProposal) SetDescription(description string) { tp.Description = description }
func (tp TextProposal) GetProposalType() ProposalKind { return tp.ProposalType }
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) 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 (p Proposals) String() string {
out := "ID - (Status) [Type] Title\n"
for _, prop := range p {
out += fmt.Sprintf("%d - (%s) [%s] %s\n",
prop.ProposalID, prop.Status,
prop.ProposalType(), prop.GetTitle())
}
return strings.TrimSpace(out)
}
func (tp TextProposal) 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`, tp.ProposalID, tp.Title, tp.ProposalType,
tp.Status, tp.SubmitTime, tp.DepositEndTime,
tp.TotalDeposit, tp.VotingStartTime, tp.VotingEndTime)
// Text Proposals
type TextProposal struct {
Title string `json:"title"` // Title of the proposal
Description string `json:"description"` // Description of the proposal
}
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
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()))
}
proposal := keeper.GetProposal(ctx, params.ProposalID)
if proposal == nil {
proposal, ok := keeper.GetProposal(ctx, params.ProposalID)
if !ok {
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
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
proposal, ok := keeper.GetProposal(ctx, proposalID)
if !ok {
return nil, ErrUnknownProposal(DefaultCodespace, proposalID)
}
var tallyResult TallyResult
if proposal.GetStatus() == StatusDepositPeriod {
if proposal.Status == StatusDepositPeriod {
tallyResult = EmptyTallyResult()
} else if proposal.GetStatus() == StatusPassed || proposal.GetStatus() == StatusRejected {
tallyResult = proposal.GetFinalTallyResult()
} else if proposal.Status == StatusPassed || proposal.Status == StatusRejected {
tallyResult = proposal.FinalTallyResult
} else {
// proposal is in voting period
_, tallyResult = tally(ctx, keeper, proposal)

View File

@ -227,12 +227,12 @@ func testQueries(t *testing.T) {
// Only proposal #1 should be in Deposit Period
proposals := getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusDepositPeriod, 0)
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
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusVotingPeriod, 0)
require.Len(t, proposals, 2)
require.Equal(t, proposalID2, proposals[0].GetProposalID())
require.Equal(t, proposalID3, proposals[1].GetProposalID())
require.Equal(t, proposalID2, proposals[0].ProposalID)
require.Equal(t, proposalID3, proposals[1].ProposalID)
// Addrs[0] votes on proposals #2 & #3
handler(ctx, NewMsgVote(addrs[0], proposalID2, OptionYes))
@ -243,8 +243,8 @@ func testQueries(t *testing.T) {
// Test query voted by addrs[0]
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, addrs[0], StatusNil, 0)
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query votes on Proposal 2
votes := getQueriedVotes(t, ctx, cdc, querier, proposalID2)
@ -263,26 +263,26 @@ func testQueries(t *testing.T) {
// Test query all proposals
proposals = getQueriedProposals(t, ctx, cdc, querier, nil, nil, StatusNil, 0)
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
require.Equal(t, proposalID2, (proposals[1]).GetProposalID())
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
require.Equal(t, proposalID2, (proposals[1]).ProposalID)
require.Equal(t, proposalID3, (proposals[2]).ProposalID)
// Test query voted by addrs[1]
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]
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
proposals = getQueriedProposals(t, ctx, cdc, querier, addrs[1], nil, StatusNil, 0)
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted AND deposited by addr1
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
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
votesIterator := keeper.GetVotes(ctx, proposal.GetProposalID())
votesIterator := keeper.GetVotes(ctx, proposal.ProposalID)
defer votesIterator.Close()
for ; votesIterator.Valid(); votesIterator.Next() {
vote := &Vote{}

View File

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

View File

@ -146,3 +146,12 @@ func SortByteArrays(src [][]byte) [][]byte {
sort.Sort(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))
}