Skip to content

Commit

Permalink
update gov strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
yutianwu committed Mar 4, 2019
1 parent fde28f3 commit b6dcc27
Show file tree
Hide file tree
Showing 20 changed files with 338 additions and 124 deletions.
1 change: 1 addition & 0 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
"title": "Test",
"description": "test",
"proposal_type": "Text",
"voting_period": "1000",
"proposer": "%s",
"initial_deposit": [{ "denom": "steak", "amount": "%d" }],
"base_req": {
Expand Down
40 changes: 33 additions & 7 deletions x/gov/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
flagTitle = "title"
flagDescription = "description"
flagProposalType = "type"
flagVotingPeriod = "voting-period"
flagDeposit = "deposit"
flagVoter = "voter"
flagOption = "option"
Expand All @@ -40,15 +41,17 @@ const (
)

type proposal struct {
Title string
Description string
Type string
Deposit string
Title string `json:"title"`
Description string `json:"description"`
VotingPeriod int64 `json:"voting_period"`
Type string `json:"type"`
Deposit string `json:"deposit"`
}

var proposalFlags = []string{
flagTitle,
flagDescription,
flagVotingPeriod,
flagProposalType,
flagDeposit,
}
Expand All @@ -68,13 +71,14 @@ where proposal.json contains:
{
"title": "Test Proposal",
"description": "My awesome proposal",
"voting_period": 1000,
"type": "Text",
"deposit": "1000:test"
}
is equivalent to
$ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="1000:test"
$ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="1000:test" --voting-period=1000
`),
RunE: func(cmd *cobra.Command, args []string) error {
proposal, err := parseSubmitProposalFlags()
Expand All @@ -99,6 +103,15 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
WithCodec(cdc).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))

if proposal.VotingPeriod <= 0 {
return errors.New("voting period should be positive")
}

votingPeriod := time.Duration(proposal.VotingPeriod) * time.Second
if votingPeriod > gov.MaxVotingPeriod {
return errors.New(fmt.Sprintf("voting period should less than %d seconds", gov.MaxVotingPeriod/time.Second))
}

fromAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
Expand All @@ -114,7 +127,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
return err
}

msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount, votingPeriod)
err = msg.ValidateBasic()
if err != nil {
return err
Expand All @@ -133,6 +146,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome

cmd.Flags().String(flagTitle, "", "title of proposal")
cmd.Flags().String(flagDescription, "", "description of proposal")
cmd.Flags().Int64(flagVotingPeriod, 7*24*60*60, "voting period in seconds")
cmd.Flags().String(flagProposalType, "", "proposalType of proposal, types: text/parameter_change/software_upgrade")
cmd.Flags().String(flagDeposit, "", "deposit of proposal")
cmd.Flags().String(flagProposal, "", "proposal file path (if this path is given, other proposal flags are ignored)")
Expand All @@ -147,6 +161,7 @@ func parseSubmitProposalFlags() (*proposal, error) {
if proposalFile == "" {
proposal.Title = viper.GetString(flagTitle)
proposal.Description = viper.GetString(flagDescription)
proposal.VotingPeriod = viper.GetInt64(flagVotingPeriod)
proposal.Type = client.NormalizeProposalType(viper.GetString(flagProposalType))
proposal.Deposit = viper.GetString(flagDeposit)
return proposal, nil
Expand Down Expand Up @@ -571,6 +586,7 @@ func GetCmdSubmitListProposal(cdc *codec.Codec) *cobra.Command {
quoteAsset := viper.GetString(flagQuoteAsset)
initPrice := viper.GetInt64(flagInitPrice)
expireTimestamp := viper.GetInt64(flagExpireTime)
votingPeriodInSeconds := viper.GetInt64(flagVotingPeriod)

if title == "" {
return errors.New("Title should not be empty")
Expand All @@ -597,6 +613,15 @@ func GetCmdSubmitListProposal(cdc *codec.Codec) *cobra.Command {
return errors.New("expire time should after now")
}

if votingPeriodInSeconds <= 0 {
return errors.New("voting period should be positive")
}

votingPeriod := time.Duration(votingPeriodInSeconds) * time.Second
if votingPeriod > gov.MaxVotingPeriod {
return errors.New(fmt.Sprintf("voting period should less than %d seconds", gov.MaxVotingPeriod/time.Second))
}

fromAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
Expand All @@ -619,7 +644,7 @@ func GetCmdSubmitListProposal(cdc *codec.Codec) *cobra.Command {
if err != nil {
return err
}
msg := gov.NewMsgSubmitProposal(title, string(listParamsBz), gov.ProposalTypeListTradingPair, fromAddr, amount)
msg := gov.NewMsgSubmitProposal(title, string(listParamsBz), gov.ProposalTypeListTradingPair, fromAddr, amount, votingPeriod)

err = msg.ValidateBasic()
if err != nil {
Expand All @@ -633,6 +658,7 @@ func GetCmdSubmitListProposal(cdc *codec.Codec) *cobra.Command {

cmd.Flags().String(flagTitle, "", "title of proposal")
cmd.Flags().String(flagDescription, "", "description of proposal")
cmd.Flags().Int64(flagVotingPeriod, 7*24*60*60, "voting period in seconds")
cmd.Flags().String(flagDeposit, "", "deposit of proposal")
cmd.Flags().String(flagBaseAsset, "", "base asset symbol")
cmd.Flags().String(flagQuoteAsset, "", "quote asset symbol")
Expand Down
5 changes: 3 additions & 2 deletions x/gov/client/cli/tx_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package cli

import (
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"io/ioutil"
"testing"

"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)

func TestParseSubmitProposalFlags(t *testing.T) {
Expand Down
21 changes: 17 additions & 4 deletions x/gov/client/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ package rest
import (
"fmt"
"net/http"
"time"

"github.com/gorilla/mux"
"github.com/pkg/errors"

"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov"

"github.com/cosmos/cosmos-sdk/x/gov/client"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)

// REST Variable names
Expand Down Expand Up @@ -44,6 +45,7 @@ type postProposalReq struct {
BaseReq utils.BaseReq `json:"base_req"`
Title string `json:"title"` // Title of the proposal
Description string `json:"description"` // Description of the proposal
VotingPeriod int64 `json:"voting_period"` // Voting period in seconds
ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer
InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit
Expand Down Expand Up @@ -81,8 +83,19 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han
return
}

if req.VotingPeriod <= 0 {
utils.WriteErrorResponse(w, http.StatusBadRequest, "voting period should be positive")
return
}

votingPeriod := time.Duration(req.VotingPeriod) * time.Second
if votingPeriod > gov.MaxVotingPeriod {
utils.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("voting period should less than %d seconds", gov.MaxVotingPeriod/time.Second))
return
}

// create the message
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, proposalType, req.Proposer, req.InitialDeposit)
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, proposalType, req.Proposer, req.InitialDeposit, votingPeriod)
err = msg.ValidateBasic()
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
Expand Down
106 changes: 96 additions & 10 deletions x/gov/endblocker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopInactiveProposalQueue(ctx, keeper))

newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[1], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)})
newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[1], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)}, 1000)

res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
Expand Down Expand Up @@ -78,7 +78,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopInactiveProposalQueue(ctx, keeper))

newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)})
newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)}, 1000)

res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
Expand All @@ -95,7 +95,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopInactiveProposalQueue(ctx, keeper))

newProposalMsg2 := gov.NewMsgSubmitProposal("Test2", "test2", gov.ProposalTypeText, addrs[1], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 5)})
newProposalMsg2 := gov.NewMsgSubmitProposal("Test2", "test2", gov.ProposalTypeText, addrs[1], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 5)}, 1000)
res = govHandler(ctx, newProposalMsg2)
require.True(t, res.IsOK())

Expand Down Expand Up @@ -131,7 +131,7 @@ func TestTickPassedDepositPeriod(t *testing.T) {
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))

newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)})
newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)}, 1000)

res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
Expand Down Expand Up @@ -177,6 +177,8 @@ func TestTickPassedVotingPeriodRejected(t *testing.T) {
// create validator
stakeKeeper.SetValidator(ctx, validator)
stakeKeeper.SetValidatorByConsAddr(ctx, validator)
stakeKeeper.Delegate(ctx, sdk.AccAddress(addrs[2]), sdk.NewCoin(gov.DefaultDepositDenom, 1000), validator, true)
stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)

govHandler := gov.NewHandler(keeper)

Expand All @@ -185,7 +187,8 @@ func TestTickPassedVotingPeriodRejected(t *testing.T) {
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))

newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)})
votingPeriod := 1000 * time.Second
newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)}, votingPeriod)

res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
Expand All @@ -201,9 +204,17 @@ func TestTickPassedVotingPeriodRejected(t *testing.T) {
require.True(t, res.IsOK())
gov.EndBlocker(ctx, keeper)

newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
newVoteMsg := gov.NewMsgVote(addrs[0], int64(proposalID), gov.OptionNo)
res = govHandler(ctx, newVoteMsg)
require.True(t, res.IsOK())
gov.EndBlocker(ctx, keeper)

// pass voting period
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetVotingProcedure(ctx).VotingPeriod)
newHeader.Time = ctx.BlockHeader().Time.Add(votingPeriod)
ctx = ctx.WithBlockHeader(newHeader)

require.True(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))
Expand All @@ -219,7 +230,6 @@ func TestTickPassedVotingPeriodRejected(t *testing.T) {
require.False(t, depositsIterator.Valid())
depositsIterator.Close()
require.Equal(t, gov.StatusRejected, keeper.GetProposal(ctx, int64(proposalID)).GetStatus())
require.True(t, keeper.GetProposal(ctx, int64(proposalID)).GetTallyResult().Equals(gov.EmptyTallyResult()))

// check distribute deposits to proposer
validatorCoins := ck.GetCoins(ctx, addrs[0])
Expand Down Expand Up @@ -248,7 +258,8 @@ func TestTickPassedVotingPeriodPassed(t *testing.T) {
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))

newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)})
votingPeriod := 1000 * time.Second
newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)}, votingPeriod)

res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
Expand All @@ -269,13 +280,12 @@ func TestTickPassedVotingPeriodPassed(t *testing.T) {
ctx = ctx.WithBlockHeader(newHeader)
newVoteMsg := gov.NewMsgVote(addrs[0], int64(proposalID), gov.OptionYes)
res = govHandler(ctx, newVoteMsg)
println(res.Log)
require.True(t, res.IsOK())
gov.EndBlocker(ctx, keeper)

// pass voting period
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetVotingProcedure(ctx).VotingPeriod)
newHeader.Time = ctx.BlockHeader().Time.Add(votingPeriod)
ctx = ctx.WithBlockHeader(newHeader)

require.True(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))
Expand All @@ -296,3 +306,79 @@ func TestTickPassedVotingPeriodPassed(t *testing.T) {
validatorCoins := ck.GetCoins(ctx, addrs[0])
require.Equal(t, validatorCoins, sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 5000e8)})
}

func TestTickPassedVotingPeriodUnreachedQuorum(t *testing.T) {
mapp, ck, keeper, stakeKeeper, addrs, pubKeys, _ := getMockApp(t, 3)

validator0 := stake.NewValidator(sdk.ValAddress(addrs[0]), pubKeys[0], stake.Description{})
validator1 := stake.NewValidator(sdk.ValAddress(addrs[1]), pubKeys[1], stake.Description{})

mapp.BeginBlock(abci.RequestBeginBlock{})
ctx := mapp.BaseApp.NewContext(sdk.RunTxModeDeliver, abci.Header{ProposerAddress: pubKeys[0].Address()})

// create and delegate validator
stakeKeeper.SetValidator(ctx, validator0)
stakeKeeper.SetValidatorByConsAddr(ctx, validator0)
stakeKeeper.SetValidator(ctx, validator1)
stakeKeeper.SetValidatorByConsAddr(ctx, validator1)
stakeKeeper.Delegate(ctx, sdk.AccAddress(addrs[2]), sdk.NewCoin(gov.DefaultDepositDenom, 1000), validator0, true)
stakeKeeper.Delegate(ctx, sdk.AccAddress(addrs[2]), sdk.NewCoin(gov.DefaultDepositDenom, 2000), validator1, true)

stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
validator0, _ = stakeKeeper.GetValidator(ctx, validator0.OperatorAddr)

govHandler := gov.NewHandler(keeper)

require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopInactiveProposalQueue(ctx, keeper))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))

votingPeriod := 1000 * time.Second
newProposalMsg := gov.NewMsgSubmitProposal("Test", "test", gov.ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)}, votingPeriod)

res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())

proposalID, _ := strconv.Atoi(string(res.Data))

newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)

newDepositMsg := gov.NewMsgDeposit(addrs[1], int64(proposalID), sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 1000e8)})
res = govHandler(ctx, newDepositMsg)
require.True(t, res.IsOK())
gov.EndBlocker(ctx, keeper)

newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
newVoteMsg := gov.NewMsgVote(addrs[0], int64(proposalID), gov.OptionYes)
res = govHandler(ctx, newVoteMsg)
require.True(t, res.IsOK())
gov.EndBlocker(ctx, keeper)

// pass voting period
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(votingPeriod)
ctx = ctx.WithBlockHeader(newHeader)

require.True(t, gov.ShouldPopActiveProposalQueue(ctx, keeper))
depositsIterator := keeper.GetDeposits(ctx, int64(proposalID))
require.True(t, depositsIterator.Valid())
depositsIterator.Close()
require.Equal(t, gov.StatusVotingPeriod, keeper.GetProposal(ctx, int64(proposalID)).GetStatus())

gov.EndBlocker(ctx, keeper)

require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
depositsIterator = keeper.GetDeposits(ctx, int64(proposalID))
require.False(t, depositsIterator.Valid())
depositsIterator.Close()
require.Equal(t, gov.StatusRejected, keeper.GetProposal(ctx, int64(proposalID)).GetStatus())

// check refund deposits
validatorCoins := ck.GetCoins(ctx, addrs[0])
require.Equal(t, validatorCoins, sdk.Coins{sdk.NewCoin(gov.DefaultDepositDenom, 5000e8)})
}
Loading

0 comments on commit b6dcc27

Please sign in to comment.