diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 9eae4ea48463..2a3157bcfa49 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -5110,6 +5110,7 @@ Proposal defines the core field members of a governance proposal. | `total_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | | `voting_start_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | | | `voting_end_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | | +| `is_expedited` | [bool](#bool) | | | @@ -5144,6 +5145,7 @@ TallyParams defines the params for tallying votes on governance proposals. | `quorum` | [bytes](#bytes) | | Minimum percentage of total stake needed to vote for a result to be considered valid. | | `threshold` | [bytes](#bytes) | | Minimum proportion of Yes votes for proposal to pass. Default value: 0.5. | | `veto_threshold` | [bytes](#bytes) | | Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Default value: 1/3. | +| `expedited_threshold` | [bytes](#bytes) | | Minimum proportion of Yes votes for an expedited proposal to pass. Default value: 0.67. | @@ -5214,6 +5216,7 @@ VotingParams defines the params for voting on governance proposals. | ----- | ---- | ----- | ----------- | | `voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | voting_period defines the length of the voting period. | | `proposal_voting_periods` | [ProposalVotingPeriod](#cosmos.gov.v1beta1.ProposalVotingPeriod) | repeated | proposal_voting_periods defines custom voting periods for proposal types. | +| `expedited_voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | expedited_voting_period defines the length of the expedited voting period. | @@ -5647,6 +5650,7 @@ proposal Content. | `content` | [google.protobuf.Any](#google.protobuf.Any) | | | | `initial_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | | `proposer` | [string](#string) | | | +| `is_expedited` | [bool](#bool) | | | diff --git a/proto/cosmos/gov/v1beta1/gov.proto b/proto/cosmos/gov/v1beta1/gov.proto index 56dff2566ec1..4935d1721b08 100644 --- a/proto/cosmos/gov/v1beta1/gov.proto +++ b/proto/cosmos/gov/v1beta1/gov.proto @@ -86,6 +86,7 @@ message Proposal { [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_start_time\""]; google.protobuf.Timestamp voting_end_time = 9 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_end_time\""]; + bool is_expedited = 10; } // ProposalStatus enumerates the valid statuses of a proposal. @@ -173,6 +174,14 @@ message VotingParams { // proposal_voting_periods defines custom voting periods for proposal types. repeated ProposalVotingPeriod proposal_voting_periods = 2 [(gogoproto.nullable) = false]; + + // expedited_voting_period defines the length of the expedited voting period. + google.protobuf.Duration expedited_voting_period = 3 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "expedited_voting_period,omitempty", + (gogoproto.moretags) = "yaml:\"expedited_voting_period\"" + ]; } // TallyParams defines the params for tallying votes on governance proposals. @@ -200,6 +209,14 @@ message TallyParams { (gogoproto.jsontag) = "veto_threshold,omitempty", (gogoproto.moretags) = "yaml:\"veto_threshold\"" ]; + + + // Minimum proportion of Yes votes for an expedited proposal to pass. Default value: 0.67. + bytes expedited_threshold = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "expedited_threshold,omitempty" + ]; } // ProposalVotingPeriod defines custom voting periods for a unique governance diff --git a/proto/cosmos/gov/v1beta1/tx.proto b/proto/cosmos/gov/v1beta1/tx.proto index 36c0a95d27d5..4017a8c91087 100644 --- a/proto/cosmos/gov/v1beta1/tx.proto +++ b/proto/cosmos/gov/v1beta1/tx.proto @@ -40,7 +40,8 @@ message MsgSubmitProposal { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.moretags) = "yaml:\"initial_deposit\"" ]; - string proposer = 3; + string proposer = 3; + bool is_expedited = 4; } // MsgSubmitProposalResponse defines the Msg/SubmitProposal response type. diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 4808b50cc26a..544e05651767 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -20,6 +20,7 @@ import ( var ( FlagCommission = "commission" FlagMaxMessagesPerTx = "max-msgs" + FlagIsExpedited = "is-expedited" ) const ( @@ -279,7 +280,7 @@ func GetCmdSubmitProposal() *cobra.Command { The proposal details must be supplied via a JSON file. Example: -$ %s tx gov submit-proposal community-pool-spend --from= +$ %s tx gov submit-proposal community-pool-spend --from= --is-expedited=false Where proposal.json contains: @@ -321,7 +322,12 @@ Where proposal.json contains: } content := types.NewCommunityPoolSpendProposal(proposal.Title, proposal.Description, recpAddr, amount) - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + isExpedited, err := cmd.Flags().GetBool(FlagIsExpedited) + if err != nil { + return err + } + + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from, isExpedited) if err != nil { return err } @@ -330,5 +336,7 @@ Where proposal.json contains: }, } + cmd.Flags().Bool(FlagIsExpedited, false, "If true, makes the proposal an expedited one") + return cmd } diff --git a/x/distribution/client/rest/rest.go b/x/distribution/client/rest/rest.go index 3fdcef89e1cc..dcad95cdf0da 100644 --- a/x/distribution/client/rest/rest.go +++ b/x/distribution/client/rest/rest.go @@ -44,7 +44,7 @@ func postProposalHandlerFn(clientCtx client.Context) http.HandlerFunc { content := types.NewCommunityPoolSpendProposal(req.Title, req.Description, req.Recipient, req.Amount) - msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) + msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer, req.IsExpedited) if rest.CheckBadRequestError(w, err) { return } diff --git a/x/distribution/client/rest/utils.go b/x/distribution/client/rest/utils.go index 3f7a3d0020ba..d9ca32eb0b06 100644 --- a/x/distribution/client/rest/utils.go +++ b/x/distribution/client/rest/utils.go @@ -12,6 +12,7 @@ type ( Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` + IsExpedited bool `json:"is_expedited" yaml:"is_expedited"` Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"` Amount sdk.Coins `json:"amount" yaml:"amount"` Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` diff --git a/x/gov/abci.go b/x/gov/abci.go index 04d6cedf5ac9..4883b25cae72 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -49,12 +49,20 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) - if burnDeposits { - keeper.DeleteDeposits(ctx, proposal.ProposalId) - } else { - keeper.RefundDeposits(ctx, proposal.ProposalId) + // If an expedited proposal fails, we do not want to update + // the deposit at this point since the proposal is converted to regular. + // As a result, the deposits are either deleted or refunded in all casses + // EXCEPT when an expedited proposal fails. + if !(proposal.IsExpedited && !passes) { + if burnDeposits { + keeper.DeleteDeposits(ctx, proposal.ProposalId) + } else { + keeper.RefundDeposits(ctx, proposal.ProposalId) + } } + keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) + if passes { handler := keeper.Router().GetRoute(proposal.ProposalRoute()) cacheCtx, writeCache := ctx.CacheContext() @@ -82,15 +90,30 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { logMsg = fmt.Sprintf("passed, but failed on execution: %s", err) } } else { - proposal.Status = types.StatusRejected - tagValue = types.AttributeValueProposalRejected - logMsg = "rejected" + if proposal.IsExpedited { + // When expedited proposal fails, it is converted + // to a regular proposal. As a result, the voting period is extended, and, + // once the regular voting period expires again, the tally is repeated + // according to the regular proposal rules. + proposal.IsExpedited = false + votingParams := keeper.GetVotingParams(ctx) + proposal.VotingEndTime = proposal.VotingStartTime.Add(votingParams.VotingPeriod) + + keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) + + tagValue = types.AttributeValueExpeditedProposalRejected + logMsg = "expedited proposal converted to regular" + } else { + // When regular proposal fails, it is rejected and + // the proposal with that id is done forever. + proposal.Status = types.StatusRejected + tagValue = types.AttributeValueProposalRejected + logMsg = "rejected" + } } proposal.FinalTallyResult = tallyResults - keeper.SetProposal(ctx, proposal) - keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) // when proposal become active keeper.AfterProposalVotingPeriodEnded(ctx, proposal.ProposalId) diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 7681bae95cf6..2d2086e815d4 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -34,6 +34,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) { types.ContentFromProposalType("test", "test", types.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], + false, ) require.NoError(t, err) @@ -86,6 +87,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { types.ContentFromProposalType("test", "test", types.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], + false, ) require.NoError(t, err) @@ -109,6 +111,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { types.ContentFromProposalType("test2", "test2", types.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], + false, ) require.NoError(t, err) @@ -166,6 +169,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { types.ContentFromProposalType("test2", "test2", types.ProposalTypeText), sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, addrs[0], + false, ) require.NoError(t, err) @@ -203,122 +207,395 @@ func TestTickPassedDepositPeriod(t *testing.T) { } func TestTickPassedVotingPeriod(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) + testcases := []struct { + name string + isExpedited bool + }{ + { + name: "regular text - deleted", + }, + { + name: "text expedited - converted to regular", + isExpedited: true, + }, + } - SortAddresses(addrs) + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + testProposal := TestProposal - header := tmproto.Header{Height: app.LastBlockHeight() + 1} - app.BeginBlock(abci.RequestBeginBlock{Header: header}) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) - govHandler := gov.NewHandler(app.GovKeeper) + SortAddresses(addrs) - inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) - require.False(t, inactiveQueue.Valid()) - inactiveQueue.Close() - activeQueue := app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) - require.False(t, activeQueue.Valid()) - activeQueue.Close() + header := tmproto.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))} - newProposalMsg, err := types.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) - require.NoError(t, err) + govHandler := gov.NewHandler(app.GovKeeper) - res, err := govHandler(ctx, newProposalMsg) - require.NoError(t, err) - require.NotNil(t, res) + inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, inactiveQueue.Valid()) + inactiveQueue.Close() + activeQueue := app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, activeQueue.Valid()) + activeQueue.Close() - var proposalData types.MsgSubmitProposalResponse - err = proto.Unmarshal(res.Data, &proposalData) - require.NoError(t, err) + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))} + newProposalMsg, err := types.NewMsgSubmitProposal(testProposal, proposalCoins, addrs[0], tc.isExpedited) + require.NoError(t, err) - proposalID := proposalData.ProposalId + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) + var proposalData types.MsgSubmitProposalResponse + err = proto.Unmarshal(res.Data, &proposalData) + require.NoError(t, err) - newDepositMsg := types.NewMsgDeposit(addrs[1], proposalID, proposalCoins) + proposalID := proposalData.ProposalId - res, err = govHandler(ctx, newDepositMsg) - require.NoError(t, err) - require.NotNil(t, res) + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) - newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) - ctx = ctx.WithBlockHeader(newHeader) + newDepositMsg := types.NewMsgDeposit(addrs[1], proposalID, proposalCoins) - inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) - require.False(t, inactiveQueue.Valid()) - inactiveQueue.Close() + res, err = govHandler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) - activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) - require.True(t, activeQueue.Valid()) + votingParams := app.GovKeeper.GetVotingParams(ctx) + newHeader = ctx.BlockHeader() + originalVotingPeriod := votingParams.VotingPeriod + if tc.isExpedited { + originalVotingPeriod = votingParams.ExpeditedVotingPeriod + } - activeProposalID := types.GetProposalIDFromBytes(activeQueue.Value()) - proposal, ok := app.GovKeeper.GetProposal(ctx, activeProposalID) - require.True(t, ok) - require.Equal(t, types.StatusVotingPeriod, proposal.Status) + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(originalVotingPeriod) + ctx = ctx.WithBlockHeader(newHeader) - activeQueue.Close() + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, inactiveQueue.Valid()) + inactiveQueue.Close() - gov.EndBlocker(ctx, app.GovKeeper) + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.True(t, activeQueue.Valid()) - activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) - require.False(t, activeQueue.Valid()) - activeQueue.Close() + activeProposalID := types.GetProposalIDFromBytes(activeQueue.Value()) + proposal, ok := app.GovKeeper.GetProposal(ctx, activeProposalID) + require.True(t, ok) + require.Equal(t, types.StatusVotingPeriod, proposal.Status) + + activeQueue.Close() + + gov.EndBlocker(ctx, app.GovKeeper) + + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + + if !tc.isExpedited { + require.False(t, activeQueue.Valid()) + activeQueue.Close() + return + } + + // If expedited, it should be converted to a regular proposal instead. + require.True(t, activeQueue.Valid()) + + activeProposalID = types.GetProposalIDFromBytes(activeQueue.Value()) + proposal, ok = app.GovKeeper.GetProposal(ctx, activeProposalID) + require.True(t, ok) + require.Equal(t, types.StatusVotingPeriod, proposal.Status) + require.False(t, proposal.IsExpedited) + + require.Equal(t, proposal.VotingStartTime.Add(votingParams.VotingPeriod), proposal.VotingEndTime) + + activeQueue.Close() + }) + } } func TestProposalPassedEndblocker(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) + testcases := []struct { + name string + IsExpedited bool + }{ + { + name: "regular text", + IsExpedited: false, + }, + { + name: "text expedited", + IsExpedited: true, + }, + } - SortAddresses(addrs) + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + testProposal := TestProposal - handler := gov.NewHandler(app.GovKeeper) - stakingHandler := staking.NewHandler(app.StakingKeeper) + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) - header := tmproto.Header{Height: app.LastBlockHeight() + 1} - app.BeginBlock(abci.RequestBeginBlock{Header: header}) + SortAddresses(addrs) - valAddr := sdk.ValAddress(addrs[0]) + handler := gov.NewHandler(app.GovKeeper) + stakingHandler := staking.NewHandler(app.StakingKeeper) - createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) - staking.EndBlocker(ctx, app.StakingKeeper) + header := tmproto.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) - macc := app.GovKeeper.GetGovernanceAccount(ctx) - require.NotNil(t, macc) - initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + valAddr := sdk.ValAddress(addrs[0]) - proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal) - require.NoError(t, err) + createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) + staking.EndBlocker(ctx, app.StakingKeeper) - proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))} - newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) + macc := app.GovKeeper.GetGovernanceAccount(ctx) + require.NotNil(t, macc) + initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) - handleAndCheck(t, handler, ctx, newDepositMsg) + proposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal, tc.IsExpedited) + require.NoError(t, err) - macc = app.GovKeeper.GetGovernanceAccount(ctx) - require.NotNil(t, macc) - moduleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))} + newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) - deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) - require.True(t, moduleAccCoins.IsEqual(deposits)) + handleAndCheck(t, handler, ctx, newDepositMsg) - err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)) - require.NoError(t, err) + macc = app.GovKeeper.GetGovernanceAccount(ctx) + require.NotNil(t, macc) + moduleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) - ctx = ctx.WithBlockHeader(newHeader) + deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) + require.True(t, moduleAccCoins.IsEqual(deposits)) - gov.EndBlocker(ctx, app.GovKeeper) + err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)) + require.NoError(t, err) + + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) + ctx = ctx.WithBlockHeader(newHeader) + + gov.EndBlocker(ctx, app.GovKeeper) + + macc = app.GovKeeper.GetGovernanceAccount(ctx) + require.NotNil(t, macc) + require.True(t, app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()).IsEqual(initialModuleAccCoins)) + }) + } +} + +func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { + testcases := []struct { + name string + // flag indicating whether the expedited proposal passes. + isExpeditedPasses bool + // flag indicating whether the converted regular proposal is expected to eventually pass + isRegularEventuallyPassing bool + }{ + { + name: "expedited passes and not converted to regular", + isExpeditedPasses: true, + }, + { + name: "expedited fails, converted to regular - regular eventually passes", + isExpeditedPasses: false, + isRegularEventuallyPassing: true, + }, + { + name: "expedited fails, converted to regular - regular eventually fails", + isExpeditedPasses: false, + isRegularEventuallyPassing: false, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + testProposal := TestProposal + + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) + + SortAddresses(addrs) + + header := tmproto.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + + valAddr := sdk.ValAddress(addrs[0]) + + stakingHandler := staking.NewHandler(app.StakingKeeper) + govHandler := gov.NewHandler(app.GovKeeper) + + // Create a validator so that able to vote on proposal. + createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) + staking.EndBlocker(ctx, app.StakingKeeper) + + inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, inactiveQueue.Valid()) + inactiveQueue.Close() + activeQueue := app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, activeQueue.Valid()) + activeQueue.Close() + + macc := app.GovKeeper.GetGovernanceAccount(ctx) + require.NotNil(t, macc) + initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + + submitterInitialBalance := app.BankKeeper.GetAllBalances(ctx, addrs[0]) + depositorInitialBalance := app.BankKeeper.GetAllBalances(ctx, addrs[1]) + + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))} + newProposalMsg, err := types.NewMsgSubmitProposal(testProposal, proposalCoins, addrs[0], true) + require.NoError(t, err) + + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) + + var proposalData types.MsgSubmitProposalResponse + err = proto.Unmarshal(res.Data, &proposalData) + require.NoError(t, err) + + proposalID := proposalData.ProposalId + + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + + newDepositMsg := types.NewMsgDeposit(addrs[1], proposalID, proposalCoins) + + res, err = govHandler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) + + votingParams := app.GovKeeper.GetVotingParams(ctx) + newHeader = ctx.BlockHeader() + + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(votingParams.ExpeditedVotingPeriod) + ctx = ctx.WithBlockHeader(newHeader) + + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, inactiveQueue.Valid()) + inactiveQueue.Close() + + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.True(t, activeQueue.Valid()) + + activeProposalID := types.GetProposalIDFromBytes(activeQueue.Value()) + proposal, ok := app.GovKeeper.GetProposal(ctx, activeProposalID) + require.True(t, ok) + require.Equal(t, types.StatusVotingPeriod, proposal.Status) + + activeQueue.Close() + + if tc.isExpeditedPasses { + // Validator votes YES, letting the expedited proposal pass. + err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)) + require.NoError(t, err) + } + + // Here the expedited proposal is converted to regular after expiry. + gov.EndBlocker(ctx, app.GovKeeper) + + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + + if tc.isExpeditedPasses { + require.False(t, activeQueue.Valid()) + + proposal, ok = app.GovKeeper.GetProposal(ctx, activeProposalID) + require.True(t, ok) + + require.Equal(t, types.StatusPassed, proposal.Status) + + submitterEventualBalance := app.BankKeeper.GetAllBalances(ctx, addrs[0]) + depositorEventualBalance := app.BankKeeper.GetAllBalances(ctx, addrs[1]) + + eventualModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + + // Module account has refunded the deposit + require.Equal(t, initialModuleAccCoins, eventualModuleAccCoins) + + require.Equal(t, submitterInitialBalance, submitterEventualBalance) + require.Equal(t, depositorInitialBalance, depositorEventualBalance) + return + } + + // Expedited proposal should be converted to a regular proposal instead. + require.True(t, activeQueue.Valid()) + + activeProposalID = types.GetProposalIDFromBytes(activeQueue.Value()) + activeQueue.Close() + + proposal, ok = app.GovKeeper.GetProposal(ctx, activeProposalID) + require.True(t, ok) + require.Equal(t, types.StatusVotingPeriod, proposal.Status) + require.False(t, proposal.IsExpedited) + require.Equal(t, proposal.VotingStartTime.Add(votingParams.VotingPeriod), proposal.VotingEndTime) + + // We also want to make sure that the deposit is not refunded yet and is still present in the module account + macc = app.GovKeeper.GetGovernanceAccount(ctx) + require.NotNil(t, macc) + intermediateModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + require.NotEqual(t, initialModuleAccCoins, intermediateModuleAccCoins) + + // Submit proposal deposit + 1 extra top up deposit + expectedIntermediateMofuleAccCoings := initialModuleAccCoins.Add(proposalCoins...).Add(proposalCoins...) + require.Equal(t, expectedIntermediateMofuleAccCoings, intermediateModuleAccCoins) + + // block header time at the voting period + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(votingParams.VotingPeriod) + ctx = ctx.WithBlockHeader(newHeader) + + inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, inactiveQueue.Valid()) + inactiveQueue.Close() + + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.True(t, activeQueue.Valid()) + + if tc.isRegularEventuallyPassing { + // Validator votes YES, letting the converted regular proposal pass. + err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)) + require.NoError(t, err) + } + + // Here we validate the converted regular proposal + gov.EndBlocker(ctx, app.GovKeeper) + + macc = app.GovKeeper.GetGovernanceAccount(ctx) + require.NotNil(t, macc) + eventualModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) + + submitterEventualBalance := app.BankKeeper.GetAllBalances(ctx, addrs[0]) + depositorEventualBalance := app.BankKeeper.GetAllBalances(ctx, addrs[1]) + + activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) + require.False(t, activeQueue.Valid()) + + proposal, ok = app.GovKeeper.GetProposal(ctx, activeProposalID) + require.True(t, ok) + + if tc.isRegularEventuallyPassing { + // Module account has refunded the deposit + require.Equal(t, initialModuleAccCoins, eventualModuleAccCoins) + require.Equal(t, submitterInitialBalance, submitterEventualBalance) + require.Equal(t, depositorInitialBalance, depositorEventualBalance) + + require.Equal(t, types.StatusPassed, proposal.Status) + return + } + + // Not enough votes - module account has burned the deposit + require.Equal(t, initialModuleAccCoins, eventualModuleAccCoins) + require.Equal(t, submitterInitialBalance.Sub(proposalCoins), submitterEventualBalance) + require.Equal(t, depositorInitialBalance.Sub(proposalCoins), depositorEventualBalance) - macc = app.GovKeeper.GetGovernanceAccount(ctx) - require.NotNil(t, macc) - require.True(t, app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()).IsEqual(initialModuleAccCoins)) + require.Equal(t, types.StatusRejected, proposal.Status) + }) + } } func TestEndBlockerProposalHandlerFailed(t *testing.T) { @@ -340,7 +617,7 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { // Create a proposal where the handler will pass for the test proposal // because the value of contextKeyBadProposal is true. ctx = ctx.WithValue(contextKeyBadProposal, true) - proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal) + proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal, false) require.NoError(t, err) proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))) diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 7e19b4838891..583142e0e389 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -20,6 +20,7 @@ import ( const ( FlagTitle = "title" FlagDescription = "description" + FlagIsExpedited = "is-expedited" FlagProposalType = "type" FlagDeposit = "deposit" flagVoter = "voter" @@ -31,6 +32,7 @@ const ( type proposal struct { Title string Description string + IsExpedited bool Type string Deposit string } @@ -98,7 +100,7 @@ Where proposal.json contains: Which is equivalent to: -$ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey +$ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --is-expedited=true --from mykey `, version.AppName, version.AppName, ), @@ -119,9 +121,14 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr return err } + isExpedited, err := cmd.Flags().GetBool(FlagIsExpedited) + if err != nil { + return err + } + content := types.ContentFromProposalType(proposal.Title, proposal.Description, proposal.Type) - msg, err := types.NewMsgSubmitProposal(content, amount, clientCtx.GetFromAddress()) + msg, err := types.NewMsgSubmitProposal(content, amount, clientCtx.GetFromAddress(), isExpedited) if err != nil { return fmt.Errorf("invalid message: %w", err) } @@ -132,6 +139,7 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr cmd.Flags().String(FlagTitle, "", "The proposal title") cmd.Flags().String(FlagDescription, "", "The proposal description") + cmd.Flags().Bool(FlagIsExpedited, false, "If true, makes the proposal an expedited one") cmd.Flags().String(FlagProposalType, "", "The proposal Type") cmd.Flags().String(FlagDeposit, "", "The proposal deposit") cmd.Flags().String(FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)") diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 46d66c240bc2..776b192c6902 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -39,6 +39,7 @@ type PostProposalReq struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` Title string `json:"title" yaml:"title"` // Title of the proposal Description string `json:"description" yaml:"description"` // Description of the proposal + IsExpedited bool `json:"is_expedited" yaml:"is_expedited"` // Flag indicating whether a proposal is expedited ProposalType string `json:"proposal_type" yaml:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal } Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` // Address of the proposer InitialDeposit sdk.Coins `json:"initial_deposit" yaml:"initial_deposit"` // Coins to add to the proposal's deposit diff --git a/x/gov/client/rest/tx.go b/x/gov/client/rest/tx.go index 284c67148170..8bb22a62b23b 100644 --- a/x/gov/client/rest/tx.go +++ b/x/gov/client/rest/tx.go @@ -39,7 +39,7 @@ func newPostProposalHandlerFn(clientCtx client.Context) http.HandlerFunc { proposalType := gcutils.NormalizeProposalType(req.ProposalType) content := types.ContentFromProposalType(req.Title, req.Description, proposalType) - msg, err := types.NewMsgSubmitProposal(content, req.InitialDeposit, req.Proposer) + msg, err := types.NewMsgSubmitProposal(content, req.InitialDeposit, req.Proposer, req.IsExpedited) if rest.CheckBadRequestError(w, err) { return } diff --git a/x/gov/client/testutil/cli_test.go b/x/gov/client/testutil/cli_test.go index 6870df4b653b..60e0b7ce8d61 100644 --- a/x/gov/client/testutil/cli_test.go +++ b/x/gov/client/testutil/cli_test.go @@ -22,7 +22,7 @@ func TestIntegrationTestSuite(t *testing.T) { genesisState := types.DefaultGenesisState() genesisState.DepositParams = types.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinDepositTokens)), time.Duration(15)*time.Second) - genesisState.VotingParams = types.NewVotingParams(time.Duration(5)*time.Second, []types.ProposalVotingPeriod{}) + genesisState.VotingParams = types.NewVotingParams(time.Duration(5)*time.Second, time.Duration(2)*time.Second, []types.ProposalVotingPeriod{}) bz, err := cfg.Codec.MarshalJSON(genesisState) require.NoError(t, err) cfg.GenesisState["gov"] = bz diff --git a/x/gov/client/testutil/suite.go b/x/gov/client/testutil/suite.go index de55c3e20184..ef3e4b38912e 100644 --- a/x/gov/client/testutil/suite.go +++ b/x/gov/client/testutil/suite.go @@ -88,7 +88,7 @@ func (s *IntegrationTestSuite) TestCmdParams() { { "json output", []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, - `{"voting_params":{"voting_period":"172800000000000","proposal_voting_periods":null},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`, + `{"voting_params":{"voting_period":"172800000000000","proposal_voting_periods":null,"expedited_voting_period":"86400000000000"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","expedited_threshold":"0.667000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`, }, { "text output", @@ -100,10 +100,12 @@ deposit_params: - amount: "10000000" denom: stake tally_params: + expedited_threshold: "0.667000000000000000" quorum: "0.334000000000000000" threshold: "0.500000000000000000" veto_threshold: "0.334000000000000000" voting_params: + expedited_voting_period: "86400000000000" proposal_voting_periods: null voting_period: "172800000000000" `, @@ -138,7 +140,7 @@ func (s *IntegrationTestSuite) TestCmdParam() { "voting", fmt.Sprintf("--%s=json", tmcli.OutputFlag), }, - `{"voting_period":"172800000000000","proposal_voting_periods":null}`, + `{"voting_period":"172800000000000","proposal_voting_periods":null,"expedited_voting_period":"86400000000000"}`, }, { "tally params", @@ -146,7 +148,7 @@ func (s *IntegrationTestSuite) TestCmdParam() { "tallying", fmt.Sprintf("--%s=json", tmcli.OutputFlag), }, - `{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"}`, + `{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","expedited_threshold":"0.667000000000000000"}`, }, { "deposit params", diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 30890937ef53..3517f9cd64f1 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -33,11 +33,11 @@ func TestImportExportQueues(t *testing.T) { // Create two proposals, put the second into the voting period proposal := TestProposal - proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal) + proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal, false) require.NoError(t, err) proposalID1 := proposal1.ProposalId - proposal2, err := app.GovKeeper.SubmitProposal(ctx, proposal) + proposal2, err := app.GovKeeper.SubmitProposal(ctx, proposal, false) require.NoError(t, err) proposalID2 := proposal2.ProposalId @@ -145,10 +145,10 @@ func TestEqualProposals(t *testing.T) { // Submit two proposals proposal := TestProposal - proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal) + proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal, false) require.NoError(t, err) - proposal2, err := app.GovKeeper.SubmitProposal(ctx, proposal) + proposal2, err := app.GovKeeper.SubmitProposal(ctx, proposal, false) require.NoError(t, err) // They are similar but their IDs should be different diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index 0c8e370681aa..9f2e5b92407e 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -18,7 +18,7 @@ func TestDeposits(t *testing.T) { TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000000)) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index fd9cb255d92e..4beb6fd73d9c 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -46,11 +46,24 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposal() { false, }, { - "valid request", + "valid request - not expedited", func() { req = &types.QueryProposalRequest{ProposalId: 1} testProposal := types.NewTextProposal("Proposal", "testing proposal") - submittedProposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal) + submittedProposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal, false) + suite.Require().NoError(err) + suite.Require().NotEmpty(submittedProposal) + + expProposal = submittedProposal + }, + true, + }, + { + "valid request - expedited", + func() { + req = &types.QueryProposalRequest{ProposalId: 2} + testProposal := types.NewTextProposal("Proposal", "testing proposal") + submittedProposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal, true) suite.Require().NoError(err) suite.Require().NotEmpty(submittedProposal) @@ -106,7 +119,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { for i := 0; i < 5; i++ { num := strconv.Itoa(i + 1) testProposal := types.NewTextProposal("Proposal"+num, "testing proposal "+num) - proposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal) + proposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal, false) suite.Require().NotEmpty(proposal) suite.Require().NoError(err) testProposals = append(testProposals, proposal) @@ -274,7 +287,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryVote() { "no votes present", func() { var err error - proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal) + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, false) suite.Require().NoError(err) req = &types.QueryVoteRequest{ @@ -379,7 +392,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryVotes() { "create a proposal and get votes", func() { var err error - proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal) + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, false) suite.Require().NoError(err) req = &types.QueryVotesRequest{ @@ -460,7 +473,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() { req = &types.QueryParamsRequest{ParamsType: types.ParamDeposit} expRes = &types.QueryParamsResponse{ DepositParams: types.DefaultDepositParams(), - TallyParams: types.NewTallyParams(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)), + TallyParams: types.NewTallyParams(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)), } }, true, @@ -471,7 +484,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() { req = &types.QueryParamsRequest{ParamsType: types.ParamVoting} expRes = &types.QueryParamsResponse{ VotingParams: types.DefaultVotingParams(), - TallyParams: types.NewTallyParams(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)), + TallyParams: types.NewTallyParams(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)), } }, true, @@ -570,7 +583,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryDeposit() { "no deposits proposal", func() { var err error - proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal) + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, false) suite.Require().NoError(err) suite.Require().NotNil(proposal) @@ -659,7 +672,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryDeposits() { "create a proposal and get deposits", func() { var err error - proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal) + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, false) suite.Require().NoError(err) req = &types.QueryDepositsRequest{ @@ -751,7 +764,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryTally() { "create a proposal and get tally", func() { var err error - proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal) + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, false) suite.Require().NoError(err) suite.Require().NotNil(proposal) diff --git a/x/gov/keeper/hooks_test.go b/x/gov/keeper/hooks_test.go index 536fc198304d..554b330ba907 100644 --- a/x/gov/keeper/hooks_test.go +++ b/x/gov/keeper/hooks_test.go @@ -63,7 +63,7 @@ func TestHooks(t *testing.T) { require.False(t, govHooksReceiver.AfterProposalVotingPeriodEndedValid) tp := TestProposal - _, err := app.GovKeeper.SubmitProposal(ctx, tp) + _, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) require.True(t, govHooksReceiver.AfterProposalSubmissionValid) @@ -74,7 +74,7 @@ func TestHooks(t *testing.T) { require.True(t, govHooksReceiver.AfterProposalFailedMinDepositValid) - p2, err := app.GovKeeper.SubmitProposal(ctx, tp) + p2, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) activated, err := app.GovKeeper.AddDeposit(ctx, p2.ProposalId, addrs[0], minDeposit) diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 105a9d002848..aa49c93c6eca 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -41,17 +41,17 @@ func TestIncrementProposalNumber(t *testing.T) { ctx := app.BaseApp.NewContext(false, tmproto.Header{}) tp := TestProposal - _, err := app.GovKeeper.SubmitProposal(ctx, tp) + _, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) - _, err = app.GovKeeper.SubmitProposal(ctx, tp) + _, err = app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) - _, err = app.GovKeeper.SubmitProposal(ctx, tp) + _, err = app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) - _, err = app.GovKeeper.SubmitProposal(ctx, tp) + _, err = app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) - _, err = app.GovKeeper.SubmitProposal(ctx, tp) + _, err = app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) - proposal6, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal6, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) require.Equal(t, uint64(6), proposal6.ProposalId) @@ -63,7 +63,7 @@ func TestProposalQueues(t *testing.T) { // create test proposals tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) inactiveIterator := app.GovKeeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime) diff --git a/x/gov/keeper/msg_server.go b/x/gov/keeper/msg_server.go index 6afebe579dbf..6ebc1a921002 100644 --- a/x/gov/keeper/msg_server.go +++ b/x/gov/keeper/msg_server.go @@ -26,7 +26,7 @@ var _ types.MsgServer = msgServer{} func (k msgServer) SubmitProposal(goCtx context.Context, msg *types.MsgSubmitProposal) (*types.MsgSubmitProposalResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - proposal, err := k.Keeper.SubmitProposal(ctx, msg.GetContent()) + proposal, err := k.Keeper.SubmitProposal(ctx, msg.GetContent(), msg.IsExpedited) if err != nil { return nil, err } diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index e9d870815246..6b64bfeef5e3 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -13,7 +13,7 @@ import ( ) // SubmitProposal create new proposal given a content -func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, error) { +func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content, isExpedited bool) (types.Proposal, error) { if !keeper.router.HasRoute(content.ProposalRoute()) { return types.Proposal{}, sdkerrors.Wrap(types.ErrNoProposalHandlerExists, content.ProposalRoute()) } @@ -35,7 +35,7 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (typ submitTime := ctx.BlockHeader().Time depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod - proposal, err := types.NewProposal(content, proposalID, submitTime, submitTime.Add(depositPeriod)) + proposal, err := types.NewProposal(content, proposalID, submitTime, submitTime.Add(depositPeriod), isExpedited) if err != nil { return types.Proposal{}, err } @@ -193,10 +193,10 @@ func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) { // voting period is used instead of the base voting period. func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) { proposal.VotingStartTime = ctx.BlockHeader().Time - proposal.Status = types.StatusVotingPeriod - votingPeriod := keeper.GetVotingPeriod(ctx, proposal.GetContent()) + votingPeriod := keeper.GetVotingParams(ctx).GetVotingPeriod(proposal.IsExpedited) proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) + proposal.Status = types.StatusVotingPeriod keeper.SetProposal(ctx, proposal) diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index a40303fceb31..e019668681d9 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -3,7 +3,9 @@ package keeper_test import ( "errors" "fmt" + "github.com/stretchr/testify/require" "strings" + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,37 +13,79 @@ import ( ) func (suite *KeeperTestSuite) TestGetSetProposal() { - tp := TestProposal - proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tp) - suite.Require().NoError(err) - proposalID := proposal.ProposalId - suite.app.GovKeeper.SetProposal(suite.ctx, proposal) - - gotProposal, ok := suite.app.GovKeeper.GetProposal(suite.ctx, proposalID) - suite.Require().True(ok) - suite.Require().True(proposal.Equal(gotProposal)) + testcases := map[string]struct { + proposal types.Content + isExpedited bool + }{ + "regular proposal": {}, + "expedited proposal": { + isExpedited: true, + }, + } + + for _, tc := range testcases { + tp := TestProposal + proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tp, tc.isExpedited) + suite.Require().NoError(err) + proposalID := proposal.ProposalId + suite.app.GovKeeper.SetProposal(suite.ctx, proposal) + + gotProposal, ok := suite.app.GovKeeper.GetProposal(suite.ctx, proposalID) + suite.Require().True(ok) + suite.Require().True(proposal.Equal(gotProposal)) + } } func (suite *KeeperTestSuite) TestActivateVotingPeriod() { - tp := TestProposal - proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tp) - suite.Require().NoError(err) + testcases := []struct { + name string + proposal types.Content + isExpedited bool + }{ + { + name: "expedited", + isExpedited: true, + }, + { + name: "not expedited", + }, + } - suite.Require().True(proposal.VotingStartTime.Equal(time.Time{})) + for _, tc := range testcases { + suite.T().Run(tc.name, func(t *testing.T) { + tp := TestProposal + proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tp, tc.isExpedited) + suite.Require().NoError(err) - suite.app.GovKeeper.ActivateVotingPeriod(suite.ctx, proposal) + suite.Require().True(proposal.VotingStartTime.Equal(time.Time{})) - suite.Require().True(proposal.VotingStartTime.Equal(suite.ctx.BlockHeader().Time)) + suite.app.GovKeeper.ActivateVotingPeriod(suite.ctx, proposal) - proposal, ok := suite.app.GovKeeper.GetProposal(suite.ctx, proposal.ProposalId) - suite.Require().True(ok) + suite.Require().True(proposal.VotingStartTime.Equal(suite.ctx.BlockHeader().Time)) - activeIterator := suite.app.GovKeeper.ActiveProposalQueueIterator(suite.ctx, proposal.VotingEndTime) - suite.Require().True(activeIterator.Valid()) + proposal, ok := suite.app.GovKeeper.GetProposal(suite.ctx, proposal.ProposalId) + suite.Require().True(ok) - proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) - suite.Require().Equal(proposalID, proposal.ProposalId) - activeIterator.Close() + activeIterator := suite.app.GovKeeper.ActiveProposalQueueIterator(suite.ctx, proposal.VotingEndTime) + suite.Require().True(activeIterator.Valid()) + + proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) + suite.Require().Equal(proposalID, proposal.ProposalId) + require.NoError(t, activeIterator.Close()) + + votingParams := suite.app.GovKeeper.GetVotingParams(suite.ctx) + + if tc.isExpedited { + require.Equal(t, proposal.VotingEndTime, proposal.VotingStartTime.Add(votingParams.ExpeditedVotingPeriod)) + } else { + require.Equal(t, proposal.VotingEndTime, proposal.VotingStartTime.Add(votingParams.VotingPeriod)) + } + + // teardown + suite.app.GovKeeper.RemoveFromActiveProposalQueue(suite.ctx, proposalID, proposal.VotingEndTime) + suite.app.GovKeeper.DeleteProposal(suite.ctx, proposalID) + }) + } } type invalidProposalRoute struct{ types.TextProposal } @@ -51,20 +95,21 @@ func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } func (suite *KeeperTestSuite) TestSubmitProposal() { testCases := []struct { content types.Content + isExpedited bool expectedErr error }{ - {&types.TextProposal{Title: "title", Description: "description"}, nil}, + {&types.TextProposal{Title: "title", Description: "description"}, true, nil}, // Keeper does not check the validity of title and description, no error - {&types.TextProposal{Title: "", Description: "description"}, nil}, - {&types.TextProposal{Title: strings.Repeat("1234567890", 100), Description: "description"}, nil}, - {&types.TextProposal{Title: "title", Description: ""}, nil}, - {&types.TextProposal{Title: "title", Description: strings.Repeat("1234567890", 1000)}, nil}, + {&types.TextProposal{Title: "", Description: "description"}, true, nil}, + {&types.TextProposal{Title: strings.Repeat("1234567890", 100), Description: "description"}, true, nil}, + {&types.TextProposal{Title: "title", Description: ""}, true, nil}, + {&types.TextProposal{Title: "title", Description: strings.Repeat("1234567890", 1000)}, true, nil}, // error only when invalid route - {&invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, + {&invalidProposalRoute{}, true, types.ErrNoProposalHandlerExists}, } for i, tc := range testCases { - _, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tc.content) + _, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tc.content, tc.isExpedited) suite.Require().True(errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) } } @@ -77,7 +122,7 @@ func (suite *KeeperTestSuite) TestGetProposalsFiltered() { for _, s := range status { for i := 0; i < 50; i++ { - p, err := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now()) + p, err := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now(), false) suite.Require().NoError(err) p.Status = s diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index b3cf4dfd923f..c40bf6c07f90 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -160,7 +160,7 @@ func TestQueries(t *testing.T) { depositParams, _, _ := getQueriedParams(t, ctx, legacyQuerierCdc, querier) // TestAddrs[0] proposes (and deposits) proposals #1 and #2 - proposal1, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal1, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) deposit1 := types.NewDeposit(proposal1.ProposalId, TestAddrs[0], oneCoins) depositer1, err := sdk.AccAddressFromBech32(deposit1.Depositor) @@ -170,7 +170,7 @@ func TestQueries(t *testing.T) { proposal1.TotalDeposit = proposal1.TotalDeposit.Add(deposit1.Amount...) - proposal2, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal2, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) deposit2 := types.NewDeposit(proposal2.ProposalId, TestAddrs[0], consCoins) depositer2, err := sdk.AccAddressFromBech32(deposit2.Depositor) @@ -181,7 +181,7 @@ func TestQueries(t *testing.T) { proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit2.Amount...) // TestAddrs[1] proposes (and deposits) on proposal #3 - proposal3, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal3, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) deposit3 := types.NewDeposit(proposal3.ProposalId, TestAddrs[1], oneCoins) depositer3, err := sdk.AccAddressFromBech32(deposit3.Depositor) diff --git a/x/gov/keeper/tally.go b/x/gov/keeper/tally.go index 07bdecf18bf4..9522d2d43bf2 100644 --- a/x/gov/keeper/tally.go +++ b/x/gov/keeper/tally.go @@ -111,8 +111,10 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo return false, true, tallyResults } - // If more than 1/2 of non-abstaining voters vote Yes, proposal passes - if results[types.OptionYes].Quo(totalVotingPower.Sub(results[types.OptionAbstain])).GT(tallyParams.Threshold) { + threshold := tallyParams.GetThreshold(proposal.IsExpedited) + // If more than threshold of non-abstaining voters vote Yes, proposal passes + // default value for regular proposals is 1/2. For expedited 2/3 + if results[types.OptionYes].Quo(totalVotingPower.Sub(results[types.OptionAbstain])).GT(threshold) { return true, false, tallyResults } diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 7347cfbe670b..505299213119 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -20,7 +20,7 @@ func TestTallyNoOneVotes(t *testing.T) { createValidators(t, ctx, app, []int64{5, 5, 5}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -44,7 +44,7 @@ func TestTallyNoQuorum(t *testing.T) { addrs := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000000)) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -67,7 +67,7 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { addrs, _ := createValidators(t, ctx, app, []int64{5, 5, 5}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -93,7 +93,7 @@ func TestTallyOnlyValidators51No(t *testing.T) { valAccAddrs, _ := createValidators(t, ctx, app, []int64{5, 6, 0}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -117,7 +117,7 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { valAccAddrs, _ := createValidators(t, ctx, app, []int64{5, 6, 0}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -142,7 +142,7 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { valAccAddrs, _ := createValidators(t, ctx, app, []int64{6, 6, 7}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -168,7 +168,7 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { valAccAddrs, _ := createValidators(t, ctx, app, []int64{6, 6, 7}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -194,7 +194,7 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { valAccAddrs, _ := createValidators(t, ctx, app, []int64{6, 6, 7}) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -221,7 +221,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1] tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -255,7 +255,7 @@ func TestTallyDelgatorOverride(t *testing.T) { _ = staking.EndBlocker(ctx, app.StakingKeeper) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -291,7 +291,7 @@ func TestTallyDelgatorInherit(t *testing.T) { _ = staking.EndBlocker(ctx, app.StakingKeeper) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -330,7 +330,7 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { _ = staking.EndBlocker(ctx, app.StakingKeeper) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -372,7 +372,7 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { _ = staking.EndBlocker(ctx, app.StakingKeeper) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -415,7 +415,7 @@ func TestTallyJailedValidator(t *testing.T) { app.StakingKeeper.Jail(ctx, sdk.ConsAddress(consAddr.Bytes())) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod @@ -448,7 +448,7 @@ func TestTallyValidatorMultipleDelegations(t *testing.T) { require.NoError(t, err) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId proposal.Status = types.StatusVotingPeriod diff --git a/x/gov/keeper/vote_test.go b/x/gov/keeper/vote_test.go index 80df4671666b..99dc6adb34de 100644 --- a/x/gov/keeper/vote_test.go +++ b/x/gov/keeper/vote_test.go @@ -18,7 +18,7 @@ func TestVotes(t *testing.T) { addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.NewInt(30000000)) tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) require.NoError(t, err) proposalID := proposal.ProposalId diff --git a/x/gov/legacy/v040/migrate_test.go b/x/gov/legacy/v040/migrate_test.go index cb47240973b9..1ac128b133e8 100644 --- a/x/gov/legacy/v040/migrate_test.go +++ b/x/gov/legacy/v040/migrate_test.go @@ -114,6 +114,7 @@ func TestMigrate(t *testing.T) { "no_with_veto": "0", "yes": "0" }, + "is_expedited": false, "proposal_id": "0", "status": "PROPOSAL_STATUS_UNSPECIFIED", "submit_time": "0001-01-01T00:00:00Z", @@ -141,6 +142,7 @@ func TestMigrate(t *testing.T) { "no_with_veto": "0", "yes": "0" }, + "is_expedited": false, "proposal_id": "0", "status": "PROPOSAL_STATUS_UNSPECIFIED", "submit_time": "0001-01-01T00:00:00Z", @@ -161,6 +163,7 @@ func TestMigrate(t *testing.T) { "no_with_veto": "0", "yes": "0" }, + "is_expedited": false, "proposal_id": "0", "status": "PROPOSAL_STATUS_UNSPECIFIED", "submit_time": "0001-01-01T00:00:00Z", @@ -188,6 +191,7 @@ func TestMigrate(t *testing.T) { "no_with_veto": "0", "yes": "0" }, + "is_expedited": false, "proposal_id": "0", "status": "PROPOSAL_STATUS_UNSPECIFIED", "submit_time": "0001-01-01T00:00:00Z", @@ -215,6 +219,7 @@ func TestMigrate(t *testing.T) { "no_with_veto": "0", "yes": "0" }, + "is_expedited": false, "proposal_id": "0", "status": "PROPOSAL_STATUS_UNSPECIFIED", "submit_time": "0001-01-01T00:00:00Z", @@ -225,12 +230,14 @@ func TestMigrate(t *testing.T) { ], "starting_proposal_id": "0", "tally_params": { + "expedited_threshold": "0", "quorum": "0", "threshold": "0", "veto_threshold": "0" }, "votes": [], "voting_params": { + "expedited_voting_period": "0s", "proposal_voting_periods": [], "voting_period": "0s" } diff --git a/x/gov/legacy/v043/json_test.go b/x/gov/legacy/v043/json_test.go index 39504a3cce36..6cdcb5b0e602 100644 --- a/x/gov/legacy/v043/json_test.go +++ b/x/gov/legacy/v043/json_test.go @@ -56,6 +56,7 @@ func TestMigrateJSON(t *testing.T) { "proposals": [], "starting_proposal_id": "0", "tally_params": { + "expedited_threshold": "0", "quorum": "0", "threshold": "0", "veto_threshold": "0" @@ -118,6 +119,7 @@ func TestMigrateJSON(t *testing.T) { } ], "voting_params": { + "expedited_voting_period": "0s", "proposal_voting_periods": [], "voting_period": "0s" } diff --git a/x/gov/simulation/decoder_test.go b/x/gov/simulation/decoder_test.go index 188fe9e540f0..49d20d45f0fd 100644 --- a/x/gov/simulation/decoder_test.go +++ b/x/gov/simulation/decoder_test.go @@ -27,9 +27,9 @@ func TestDecodeStore(t *testing.T) { endTime := time.Now().UTC() content := types.ContentFromProposalType("test", "test", types.ProposalTypeText) - proposalA, err := types.NewProposal(content, 1, endTime, endTime.Add(24*time.Hour)) + proposalA, err := types.NewProposal(content, 1, endTime, endTime.Add(24*time.Hour), false) require.NoError(t, err) - proposalB, err := types.NewProposal(content, 2, endTime, endTime.Add(24*time.Hour)) + proposalB, err := types.NewProposal(content, 2, endTime, endTime.Add(24*time.Hour), false) require.NoError(t, err) proposalIDBz := make([]byte, 8) diff --git a/x/gov/simulation/genesis.go b/x/gov/simulation/genesis.go index ad7451294e58..d7ef7c2e5351 100644 --- a/x/gov/simulation/genesis.go +++ b/x/gov/simulation/genesis.go @@ -16,12 +16,22 @@ import ( // Simulation parameter constants const ( - DepositParamsMinDeposit = "deposit_params_min_deposit" - DepositParamsDepositPeriod = "deposit_params_deposit_period" - VotingParamsVotingPeriod = "voting_params_voting_period" - TallyParamsQuorum = "tally_params_quorum" - TallyParamsThreshold = "tally_params_threshold" - TallyParamsVeto = "tally_params_veto" + DepositParamsMinDeposit = "deposit_params_min_deposit" + DepositParamsDepositPeriod = "deposit_params_deposit_period" + VotingParamsVotingPeriod = "voting_params_voting_period" + ExpeditedVotingParamsVotingPeriod = "expedited_voting_params_voting_period" + TallyParamsQuorum = "tally_params_quorum" + TallyParamsThreshold = "tally_params_threshold" + TallyParamsExpeditedThreshold = "tally_params_expedited_threshold" + TallyParamsVeto = "tally_params_veto" + + // ExpeditedThreshold must be at least as large as the regular Threshold + // Therefore, we use this break out point in randomization. + tallyNonExpeditedMax = 500 + + // Similarly, expedited voting period must be strictly less than the regular + // voting period to be valid. Therefore, we use this break out point in randomization. + expeditedMaxVotingPeriod = 60 * 60 * 24 * 2 ) // GenDepositParamsDepositPeriod randomized DepositParamsDepositPeriod @@ -36,7 +46,12 @@ func GenDepositParamsMinDeposit(r *rand.Rand) sdk.Coins { // GenVotingParamsVotingPeriod randomized VotingParamsVotingPeriod func GenVotingParamsVotingPeriod(r *rand.Rand) time.Duration { - return time.Duration(simulation.RandIntBetween(r, 1, 2*60*60*24*2)) * time.Second + return time.Duration(simulation.RandIntBetween(r, expeditedMaxVotingPeriod, 2*expeditedMaxVotingPeriod)) * time.Second +} + +// GenVotingParamsExpeditedVotingPeriod randomized VotingParamsExpeditedVotingPeriod +func GenVotingParamsExpeditedVotingPeriod(r *rand.Rand) time.Duration { + return time.Duration(simulation.RandIntBetween(r, 1, expeditedMaxVotingPeriod)) * time.Second } // GenTallyParamsQuorum randomized TallyParamsQuorum @@ -46,7 +61,12 @@ func GenTallyParamsQuorum(r *rand.Rand) sdk.Dec { // GenTallyParamsThreshold randomized TallyParamsThreshold func GenTallyParamsThreshold(r *rand.Rand) sdk.Dec { - return sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, 450, 550)), 3) + return sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, 450, tallyNonExpeditedMax)), 3) +} + +// GenTallyParamsExpeditedThreshold randomized TallyParamsExpeditedThreshold +func GenTallyParamsExpeditedThreshold(r *rand.Rand) sdk.Dec { + return sdk.NewDecWithPrec(int64(simulation.RandIntBetween(r, tallyNonExpeditedMax+1, 550)), 3) } // GenTallyParamsVeto randomized TallyParamsVeto @@ -76,6 +96,12 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { votingPeriod = GenVotingParamsVotingPeriod(r) }, ) + var expeditedVotingPeriod time.Duration + simState.AppParams.GetOrGenerate( + simState.Cdc, ExpeditedVotingParamsVotingPeriod, &expeditedVotingPeriod, simState.Rand, + func(r *rand.Rand) { expeditedVotingPeriod = GenVotingParamsExpeditedVotingPeriod(r) }, + ) + var quorum sdk.Dec simState.AppParams.GetOrGenerate( simState.Cdc, TallyParamsQuorum, &quorum, simState.Rand, @@ -88,6 +114,12 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { threshold = GenTallyParamsThreshold(r) }, ) + var expeditedThreshold sdk.Dec + simState.AppParams.GetOrGenerate( + simState.Cdc, TallyParamsExpeditedThreshold, &expeditedThreshold, simState.Rand, + func(r *rand.Rand) { expeditedThreshold = GenTallyParamsExpeditedThreshold(r) }, + ) + var veto sdk.Dec simState.AppParams.GetOrGenerate( simState.Cdc, TallyParamsVeto, &veto, simState.Rand, @@ -112,8 +144,8 @@ func RandomizedGenState(simState *module.SimulationState) { govGenesis := types.NewGenesisState( startingProposalID, types.NewDepositParams(minDeposit, depositPeriod), - types.NewVotingParams(votingPeriod, proposalVotingPeriods), - types.NewTallyParams(quorum, threshold, veto), + types.NewVotingParams(votingPeriod, expeditedVotingPeriod, proposalVotingPeriods), + types.NewTallyParams(quorum, threshold, expeditedThreshold, veto), ) bz, err := json.MarshalIndent(&govGenesis, "", " ") diff --git a/x/gov/simulation/genesis_test.go b/x/gov/simulation/genesis_test.go index db8b98bff103..e3bf9a8e0a2a 100644 --- a/x/gov/simulation/genesis_test.go +++ b/x/gov/simulation/genesis_test.go @@ -40,16 +40,19 @@ func TestRandomizedGenState(t *testing.T) { var govGenesis types.GenesisState simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &govGenesis) - dec1, _ := sdk.NewDecFromStr("0.361000000000000000") - dec2, _ := sdk.NewDecFromStr("0.512000000000000000") - dec3, _ := sdk.NewDecFromStr("0.267000000000000000") + dec1, _ := sdk.NewDecFromStr("0.400000000000000000") + dec2, _ := sdk.NewDecFromStr("0.489000000000000000") + dec3, _ := sdk.NewDecFromStr("0.509000000000000000") + dec4, _ := sdk.NewDecFromStr("0.324000000000000000") require.Equal(t, "905stake", govGenesis.DepositParams.MinDeposit.String()) require.Equal(t, "77h26m10s", govGenesis.DepositParams.MaxDepositPeriod.String()) - require.Equal(t, float64(148296), govGenesis.VotingParams.VotingPeriod.Seconds()) + require.Equal(t, float64(317894), govGenesis.VotingParams.VotingPeriod.Seconds()) + require.Equal(t, float64(107823), govGenesis.VotingParams.ExpeditedVotingPeriod.Seconds()) require.Equal(t, dec1, govGenesis.TallyParams.Quorum) require.Equal(t, dec2, govGenesis.TallyParams.Threshold) - require.Equal(t, dec3, govGenesis.TallyParams.VetoThreshold) + require.Equal(t, dec3, govGenesis.TallyParams.ExpeditedThreshold) + require.Equal(t, dec4, govGenesis.TallyParams.VetoThreshold) require.Equal(t, uint64(0x28), govGenesis.StartingProposalId) require.Equal(t, types.Deposits{}, govGenesis.Deposits) require.Equal(t, types.Votes{}, govGenesis.Votes) diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 214fb9465676..1290a058968b 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -137,7 +137,7 @@ func SimulateMsgSubmitProposal( return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSubmitProposal, "unable to generate deposit"), nil, err } - msg, err := types.NewMsgSubmitProposal(content, deposit, simAccount.Address) + msg, err := types.NewMsgSubmitProposal(content, deposit, simAccount.Address, r.Intn(2) == 0) if err != nil { return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate a submit proposal msg"), nil, err } diff --git a/x/gov/simulation/operations_test.go b/x/gov/simulation/operations_test.go index 6a5252dc3785..b908b5cd814b 100644 --- a/x/gov/simulation/operations_test.go +++ b/x/gov/simulation/operations_test.go @@ -122,6 +122,7 @@ func TestSimulateMsgSubmitProposal(t *testing.T) { require.Equal(t, "description-3: NJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeH", msg.GetContent().GetDescription()) require.Equal(t, "gov", msg.Route()) require.Equal(t, types.TypeMsgSubmitProposal, msg.Type()) + require.True(t, msg.IsExpedited) } // TestSimulateMsgDeposit tests the normal scenario of a valid message of type TypeMsgDeposit. @@ -142,7 +143,7 @@ func TestSimulateMsgDeposit(t *testing.T) { submitTime := ctx.BlockHeader().Time depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod - proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod)) + proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod), false) require.NoError(t, err) app.GovKeeper.SetProposal(ctx, proposal) @@ -184,7 +185,7 @@ func TestSimulateMsgVote(t *testing.T) { submitTime := ctx.BlockHeader().Time depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod - proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod)) + proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod), false) require.NoError(t, err) app.GovKeeper.ActivateVotingPeriod(ctx, proposal) @@ -226,7 +227,7 @@ func TestSimulateMsgVoteWeighted(t *testing.T) { submitTime := ctx.BlockHeader().Time depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod - proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod)) + proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod), false) require.NoError(t, err) app.GovKeeper.ActivateVotingPeriod(ctx, proposal) diff --git a/x/gov/simulation/params.go b/x/gov/simulation/params.go index c0f0ac05aecf..4ddf5a77c693 100644 --- a/x/gov/simulation/params.go +++ b/x/gov/simulation/params.go @@ -14,12 +14,13 @@ import ( ) const ( - keyVotingParams = "votingparams" - keyDepositParams = "depositparams" - keyTallyParams = "tallyparams" - subkeyQuorum = "quorum" - subkeyThreshold = "threshold" - subkeyVeto = "veto" + keyVotingParams = "votingparams" + keyDepositParams = "depositparams" + keyTallyParams = "tallyparams" + subkeyQuorum = "quorum" + subkeyThreshold = "threshold" + subkeyExpeditedThreshold = "expedited_threshold" + subkeyVeto = "veto" ) // ParamChanges defines the parameters that can be modified by param change proposals @@ -31,6 +32,11 @@ func ParamChanges(r *rand.Rand) []simtypes.ParamChange { return fmt.Sprintf(`{"voting_period": "%d"}`, GenVotingParamsVotingPeriod(r)) }, ), + simulation.NewSimParamChange(types.ModuleName, keyVotingParams, + func(r *rand.Rand) string { + return fmt.Sprintf(`{"expedited_voting_period": "%d"}`, GenVotingParamsExpeditedVotingPeriod(r)) + }, + ), simulation.NewSimParamChange(types.ModuleName, keyDepositParams, func(r *rand.Rand) string { return fmt.Sprintf(`{"max_deposit_period": "%d"}`, GenDepositParamsDepositPeriod(r)) @@ -44,6 +50,7 @@ func ParamChanges(r *rand.Rand) []simtypes.ParamChange { }{ {subkeyQuorum, GenTallyParamsQuorum(r)}, {subkeyThreshold, GenTallyParamsThreshold(r)}, + {subkeyExpeditedThreshold, GenTallyParamsExpeditedThreshold(r)}, {subkeyVeto, GenTallyParamsVeto(r)}, } diff --git a/x/gov/simulation/params_test.go b/x/gov/simulation/params_test.go index de528d14d9d5..e11319dc7fb4 100644 --- a/x/gov/simulation/params_test.go +++ b/x/gov/simulation/params_test.go @@ -19,13 +19,14 @@ func TestParamChanges(t *testing.T) { simValue string subspace string }{ - {"gov/votingparams", "votingparams", "{\"voting_period\": \"82639000000000\"}", "gov"}, - {"gov/depositparams", "depositparams", "{\"max_deposit_period\": \"47332000000000\"}", "gov"}, - {"gov/tallyparams", "tallyparams", "{\"threshold\":\"0.509000000000000000\"}", "gov"}, + {"gov/votingparams", "votingparams", "{\"voting_period\": \"251681000000000\"}", "gov"}, + {"gov/votingparams", "votingparams", "{\"expedited_voting_period\": \"53176000000000\"}", "gov"}, + {"gov/depositparams", "depositparams", "{\"max_deposit_period\": \"153577000000000\"}", "gov"}, + {"gov/tallyparams", "tallyparams", "{\"quorum\":\"0.429000000000000000\",\"veto\":\"0.323000000000000000\"}", "gov"}, } paramChanges := simulation.ParamChanges(r) - require.Len(t, paramChanges, 3) + require.Len(t, paramChanges, 4) for i, p := range paramChanges { diff --git a/x/gov/spec/01_concepts.md b/x/gov/spec/01_concepts.md index 29e582990b09..d4b5739bf692 100644 --- a/x/gov/spec/01_concepts.md +++ b/x/gov/spec/01_concepts.md @@ -137,6 +137,10 @@ For a weighted vote to be valid, the `options` field must not contain duplicate Quorum is defined as the minimum percentage of voting power that needs to be casted on a proposal for the result to be valid. +### Expedited Proposals + +A proposal can be expedited, making the proposal use shorter voting duration and a higher tally threshold by its default. If an expedited proposal fails to meet the threshold within the scope of shorter voting duration, the expedited proposal is then converted to a regular proposal and restarts voting under regular voting conditions. + ### Threshold Threshold is defined as the minimum proportion of `Yes` votes (excluding @@ -149,6 +153,8 @@ that proposals are accepted if the proportion of `Yes` votes (excluding proportion of `NoWithVeto` votes is inferior to 1/3 (excluding `Abstain` votes). +For expedited proposals, it has a higher minimum threshold as its initial parameter, set at 66.7%. + ### Inheritance If a delegator does not vote, it will inherit its validator vote. diff --git a/x/gov/types/events.go b/x/gov/types/events.go index 19f8857f3a1c..8bfdc67caca4 100644 --- a/x/gov/types/events.go +++ b/x/gov/types/events.go @@ -8,14 +8,15 @@ const ( EventTypeInactiveProposal = "inactive_proposal" EventTypeActiveProposal = "active_proposal" - AttributeKeyProposalResult = "proposal_result" - AttributeKeyOption = "option" - AttributeKeyProposalID = "proposal_id" - AttributeKeyVotingPeriodStart = "voting_period_start" - AttributeValueCategory = "governance" - AttributeValueProposalDropped = "proposal_dropped" // didn't meet min deposit - AttributeValueProposalPassed = "proposal_passed" // met vote quorum - AttributeValueProposalRejected = "proposal_rejected" // didn't meet vote quorum - AttributeValueProposalFailed = "proposal_failed" // error on proposal handler - AttributeKeyProposalType = "proposal_type" + AttributeKeyProposalResult = "proposal_result" + AttributeKeyOption = "option" + AttributeKeyProposalID = "proposal_id" + AttributeKeyVotingPeriodStart = "voting_period_start" + AttributeValueCategory = "governance" + AttributeValueProposalDropped = "proposal_dropped" // didn't meet min deposit + AttributeValueProposalPassed = "proposal_passed" // met vote quorum + AttributeValueProposalRejected = "proposal_rejected" // didn't meet vote quorum + AttributeValueExpeditedProposalRejected = "expedited_proposal_rejected" // didn't meet expedited vote quorum + AttributeValueProposalFailed = "proposal_failed" // error on proposal handler + AttributeKeyProposalType = "proposal_type" ) diff --git a/x/gov/types/genesis.go b/x/gov/types/genesis.go index 7f2d138ae300..84fed2e13f87 100644 --- a/x/gov/types/genesis.go +++ b/x/gov/types/genesis.go @@ -50,6 +50,18 @@ func ValidateGenesis(data *GenesisState) error { threshold.String()) } + expeditedThreshold := data.TallyParams.ExpeditedThreshold + if expeditedThreshold.IsNegative() || expeditedThreshold.GT(sdk.OneDec()) { + return fmt.Errorf("governance expedited vote threshold should be positive and less or equal to one, is %s", + expeditedThreshold) + } + + if expeditedThreshold.LTE(threshold) { + return fmt.Errorf("expedited governance vote threshold %s should be greater than the regular threshold %s", + expeditedThreshold, + threshold) + } + veto := data.TallyParams.VetoThreshold if veto.IsNegative() || veto.GT(sdk.OneDec()) { return fmt.Errorf("governance vote veto threshold should be positive and less or equal to one, is %s", diff --git a/x/gov/types/gov.pb.go b/x/gov/types/gov.pb.go index 6cccc4e0e0ea..b0ed836e3270 100644 --- a/x/gov/types/gov.pb.go +++ b/x/gov/types/gov.pb.go @@ -251,6 +251,7 @@ type Proposal struct { TotalDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,7,rep,name=total_deposit,json=totalDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"total_deposit" yaml:"total_deposit"` VotingStartTime time.Time `protobuf:"bytes,8,opt,name=voting_start_time,json=votingStartTime,proto3,stdtime" json:"voting_start_time" yaml:"voting_start_time"` VotingEndTime time.Time `protobuf:"bytes,9,opt,name=voting_end_time,json=votingEndTime,proto3,stdtime" json:"voting_end_time" yaml:"voting_end_time"` + IsExpedited bool `protobuf:"varint,10,opt,name=is_expedited,json=isExpedited,proto3" json:"is_expedited,omitempty"` } func (m *Proposal) Reset() { *m = Proposal{} } @@ -417,6 +418,8 @@ type VotingParams struct { VotingPeriod time.Duration `protobuf:"bytes,1,opt,name=voting_period,json=votingPeriod,proto3,stdduration" json:"voting_period,omitempty" yaml:"voting_period"` // proposal_voting_periods defines custom voting periods for proposal types. ProposalVotingPeriods []ProposalVotingPeriod `protobuf:"bytes,2,rep,name=proposal_voting_periods,json=proposalVotingPeriods,proto3" json:"proposal_voting_periods"` + // expedited_voting_period defines the length of the expedited voting period. + ExpeditedVotingPeriod time.Duration `protobuf:"bytes,3,opt,name=expedited_voting_period,json=expeditedVotingPeriod,proto3,stdduration" json:"expedited_voting_period,omitempty" yaml:"expedited_voting_period"` } func (m *VotingParams) Reset() { *m = VotingParams{} } @@ -461,6 +464,8 @@ type TallyParams struct { // Minimum value of Veto votes to Total votes ratio for proposal to be // vetoed. Default value: 1/3. VetoThreshold github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=veto_threshold,json=vetoThreshold,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"veto_threshold,omitempty" yaml:"veto_threshold"` + // Minimum proportion of Yes votes for an expedited proposal to pass. Default value: 0.67. + ExpeditedThreshold github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=expedited_threshold,json=expeditedThreshold,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"expedited_threshold,omitempty"` } func (m *TallyParams) Reset() { *m = TallyParams{} } @@ -552,102 +557,107 @@ func init() { func init() { proto.RegisterFile("cosmos/gov/v1beta1/gov.proto", fileDescriptor_6e82113c1a9a4b7c) } var fileDescriptor_6e82113c1a9a4b7c = []byte{ - // 1511 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x41, 0x6c, 0x1a, 0x47, - 0x17, 0x66, 0x01, 0x63, 0x33, 0x80, 0x4d, 0xc6, 0xc4, 0xc6, 0xfc, 0xf9, 0x59, 0xba, 0xa9, 0x22, - 0x2b, 0x4a, 0x70, 0xe2, 0x56, 0xad, 0xea, 0x48, 0x6d, 0xc1, 0xe0, 0x86, 0x2a, 0x02, 0xb4, 0x6c, - 0xb0, 0x92, 0x1e, 0x56, 0x6b, 0x18, 0xe3, 0x6d, 0xd9, 0x1d, 0xca, 0x0e, 0x8e, 0x51, 0x2f, 0x3d, - 0x46, 0x1c, 0xaa, 0x1c, 0x23, 0x55, 0x48, 0x91, 0xaa, 0x5e, 0x7a, 0xee, 0xa1, 0xa7, 0x9e, 0xad, - 0xaa, 0x52, 0xa3, 0x9e, 0xa2, 0x56, 0x22, 0x8d, 0x2d, 0x55, 0x91, 0x8f, 0xae, 0xd4, 0x73, 0xb5, - 0x3b, 0xb3, 0xb0, 0x0b, 0x56, 0x1c, 0x7a, 0xe8, 0x89, 0xdd, 0x37, 0xef, 0xfb, 0xbe, 0xf7, 0xde, - 0xbc, 0x37, 0xb3, 0x80, 0x4b, 0x35, 0x6c, 0x68, 0xd8, 0x58, 0x6b, 0xe0, 0xfd, 0xb5, 0xfd, 0x9b, - 0x3b, 0x88, 0x28, 0x37, 0xcd, 0xe7, 0x74, 0xab, 0x8d, 0x09, 0x86, 0x90, 0xae, 0xa6, 0x4d, 0x0b, - 0x5b, 0x4d, 0x24, 0x19, 0x62, 0x47, 0x31, 0xd0, 0x10, 0x52, 0xc3, 0xaa, 0x4e, 0x31, 0x89, 0x58, - 0x03, 0x37, 0xb0, 0xf5, 0xb8, 0x66, 0x3e, 0x31, 0xeb, 0x0a, 0x45, 0xc9, 0x74, 0x81, 0xd1, 0xd2, - 0x25, 0xbe, 0x81, 0x71, 0xa3, 0x89, 0xd6, 0xac, 0xb7, 0x9d, 0xce, 0xee, 0x1a, 0x51, 0x35, 0x64, - 0x10, 0x45, 0x6b, 0xd9, 0xd8, 0x71, 0x07, 0x45, 0xef, 0xb2, 0xa5, 0xe4, 0xf8, 0x52, 0xbd, 0xd3, - 0x56, 0x88, 0x8a, 0x59, 0x30, 0xc2, 0xb7, 0x1c, 0x80, 0xdb, 0x48, 0x6d, 0xec, 0x11, 0x54, 0xaf, - 0x62, 0x82, 0x4a, 0x2d, 0x73, 0x11, 0xbe, 0x03, 0x02, 0xd8, 0x7a, 0x8a, 0x73, 0x29, 0x6e, 0x75, - 0x7e, 0x3d, 0x99, 0x9e, 0x4c, 0x34, 0x3d, 0xf2, 0x17, 0x99, 0x37, 0xdc, 0x06, 0x81, 0x07, 0x16, - 0x5b, 0xdc, 0x9b, 0xe2, 0x56, 0x83, 0xd9, 0x0f, 0x0e, 0x07, 0xbc, 0xe7, 0xb7, 0x01, 0x7f, 0xa5, - 0xa1, 0x92, 0xbd, 0xce, 0x4e, 0xba, 0x86, 0x35, 0x96, 0x1b, 0xfb, 0xb9, 0x6e, 0xd4, 0x3f, 0x5b, - 0x23, 0xdd, 0x16, 0x32, 0xd2, 0x39, 0x54, 0x3b, 0x1d, 0xf0, 0x91, 0xae, 0xa2, 0x35, 0x37, 0x04, - 0xca, 0x22, 0x88, 0x8c, 0x4e, 0xd8, 0x06, 0x61, 0x09, 0x1d, 0x90, 0x72, 0x1b, 0xb7, 0xb0, 0xa1, - 0x34, 0x61, 0x0c, 0xcc, 0x10, 0x95, 0x34, 0x91, 0x15, 0x5f, 0x50, 0xa4, 0x2f, 0x30, 0x05, 0x42, - 0x75, 0x64, 0xd4, 0xda, 0x2a, 0x8d, 0xdd, 0x8a, 0x41, 0x74, 0x9a, 0x36, 0x16, 0x5e, 0x3e, 0xe1, - 0xb9, 0x5f, 0xbf, 0xbf, 0x3e, 0xbb, 0x89, 0x75, 0x82, 0x74, 0x22, 0xfc, 0xc2, 0x81, 0xd9, 0x1c, - 0x6a, 0x61, 0x43, 0x25, 0xf0, 0x5d, 0x10, 0x6a, 0x31, 0x01, 0x59, 0xad, 0x5b, 0xd4, 0xfe, 0xec, - 0xd2, 0xe9, 0x80, 0x87, 0x34, 0x28, 0xc7, 0xa2, 0x20, 0x02, 0xfb, 0xad, 0x50, 0x87, 0x97, 0x40, - 0xb0, 0x4e, 0x39, 0x70, 0x9b, 0xa9, 0x8e, 0x0c, 0xb0, 0x06, 0x02, 0x8a, 0x86, 0x3b, 0x3a, 0x89, - 0xfb, 0x52, 0xbe, 0xd5, 0xd0, 0xfa, 0x8a, 0x5d, 0x4c, 0xb3, 0x43, 0x86, 0xd5, 0xdc, 0xc4, 0xaa, - 0x9e, 0xbd, 0x61, 0xd6, 0xeb, 0xbb, 0xe7, 0xfc, 0xea, 0x6b, 0xd4, 0xcb, 0x04, 0x18, 0x22, 0xa3, - 0xde, 0x98, 0x7b, 0xf8, 0x84, 0xf7, 0xbc, 0x7c, 0xc2, 0x7b, 0x84, 0xbf, 0x03, 0x60, 0x6e, 0x58, - 0xa7, 0xb7, 0xcf, 0x4a, 0x69, 0xf1, 0x64, 0xc0, 0x7b, 0xd5, 0xfa, 0xe9, 0x80, 0x0f, 0xd2, 0xc4, - 0xc6, 0xf3, 0xb9, 0x05, 0x66, 0x6b, 0xb4, 0x3e, 0x56, 0x36, 0xa1, 0xf5, 0x58, 0x9a, 0xf6, 0x51, - 0xda, 0xee, 0xa3, 0x74, 0x46, 0xef, 0x66, 0x43, 0x3f, 0x8d, 0x0a, 0x29, 0xda, 0x08, 0x58, 0x05, - 0x01, 0x83, 0x28, 0xa4, 0x63, 0xc4, 0x7d, 0x56, 0xef, 0x08, 0x67, 0xf5, 0x8e, 0x1d, 0x60, 0xc5, - 0xf2, 0xcc, 0x26, 0x4e, 0x07, 0xfc, 0xd2, 0x58, 0x91, 0x29, 0x89, 0x20, 0x32, 0x36, 0xd8, 0x02, - 0x70, 0x57, 0xd5, 0x95, 0xa6, 0x4c, 0x94, 0x66, 0xb3, 0x2b, 0xb7, 0x91, 0xd1, 0x69, 0x92, 0xb8, - 0xdf, 0x8a, 0x8f, 0x3f, 0x4b, 0x43, 0x32, 0xfd, 0x44, 0xcb, 0x2d, 0xfb, 0x86, 0x59, 0xd8, 0xd3, - 0x01, 0xbf, 0x42, 0x45, 0x26, 0x89, 0x04, 0x31, 0x6a, 0x19, 0x1d, 0x20, 0xf8, 0x09, 0x08, 0x19, - 0x9d, 0x1d, 0x4d, 0x25, 0xb2, 0x39, 0x71, 0xf1, 0x19, 0x4b, 0x2a, 0x31, 0x51, 0x0a, 0xc9, 0x1e, - 0xc7, 0x6c, 0x92, 0xa9, 0xb0, 0x7e, 0x71, 0x80, 0x85, 0x47, 0xcf, 0x79, 0x4e, 0x04, 0xd4, 0x62, - 0x02, 0xa0, 0x0a, 0xa2, 0xac, 0x45, 0x64, 0xa4, 0xd7, 0xa9, 0x42, 0xe0, 0x5c, 0x85, 0xcb, 0x4c, - 0x61, 0x99, 0x2a, 0x8c, 0x33, 0x50, 0x99, 0x79, 0x66, 0xce, 0xeb, 0x75, 0x4b, 0xea, 0x21, 0x07, - 0x22, 0x04, 0x13, 0xa5, 0x29, 0xb3, 0x85, 0xf8, 0xec, 0x79, 0x8d, 0x78, 0x9b, 0xe9, 0xc4, 0xa8, - 0x8e, 0x0b, 0x2d, 0x4c, 0xd5, 0xa0, 0x61, 0x0b, 0x6b, 0x8f, 0x58, 0x13, 0x5c, 0xd8, 0xc7, 0x44, - 0xd5, 0x1b, 0xe6, 0xf6, 0xb6, 0x59, 0x61, 0xe7, 0xce, 0x4d, 0xfb, 0x4d, 0x16, 0x4e, 0x9c, 0x86, - 0x33, 0x41, 0x41, 0xf3, 0x5e, 0xa0, 0xf6, 0x8a, 0x69, 0xb6, 0x12, 0xdf, 0x05, 0xcc, 0x34, 0x2a, - 0x71, 0xf0, 0x5c, 0x2d, 0x81, 0x69, 0x2d, 0xb9, 0xb4, 0xdc, 0x15, 0x8e, 0x50, 0x2b, 0x2b, 0xf0, - 0x86, 0xdf, 0x3c, 0x55, 0x84, 0x43, 0x2f, 0x08, 0x39, 0xdb, 0xe7, 0x43, 0xe0, 0xeb, 0x22, 0x83, - 0x9e, 0x50, 0xd9, 0xf4, 0x14, 0x27, 0x61, 0x41, 0x27, 0xa2, 0x09, 0x85, 0xb7, 0xc1, 0xac, 0xb2, - 0x63, 0x10, 0x45, 0x65, 0x67, 0xd9, 0xd4, 0x2c, 0x36, 0x1c, 0xbe, 0x0f, 0xbc, 0x3a, 0xb6, 0x06, - 0x72, 0x7a, 0x12, 0xaf, 0x8e, 0x61, 0x03, 0x84, 0x75, 0x2c, 0x3f, 0x50, 0xc9, 0x9e, 0xbc, 0x8f, - 0x08, 0xb6, 0xc6, 0x2e, 0x98, 0xcd, 0x4f, 0xc7, 0x74, 0x3a, 0xe0, 0x17, 0x69, 0x51, 0x9d, 0x5c, - 0x82, 0x08, 0x74, 0xbc, 0xad, 0x92, 0xbd, 0x2a, 0x22, 0x98, 0x95, 0xf2, 0x98, 0x03, 0x7e, 0xf3, - 0x7a, 0xf9, 0xf7, 0x47, 0x72, 0x0c, 0xcc, 0xec, 0x63, 0x82, 0xec, 0xe3, 0x98, 0xbe, 0xc0, 0x8d, - 0xe1, 0xbd, 0xe6, 0x7b, 0x9d, 0x7b, 0x2d, 0xeb, 0x8d, 0x73, 0xc3, 0xbb, 0x6d, 0x0b, 0xcc, 0xd2, - 0x27, 0x23, 0xee, 0xb7, 0xc6, 0xe7, 0xca, 0x59, 0xe0, 0xc9, 0xcb, 0x34, 0xeb, 0x37, 0xab, 0x24, - 0xda, 0xe0, 0x8d, 0xb9, 0xc7, 0xf6, 0x49, 0xfd, 0xa3, 0x17, 0x44, 0xd8, 0x60, 0x94, 0x95, 0xb6, - 0xa2, 0x19, 0xf0, 0x6b, 0x0e, 0x84, 0x34, 0x55, 0x1f, 0xce, 0x29, 0x77, 0xde, 0x9c, 0xca, 0x26, - 0xf7, 0xc9, 0x80, 0xbf, 0xe8, 0x40, 0x5d, 0xc3, 0x9a, 0x4a, 0x90, 0xd6, 0x22, 0xdd, 0x51, 0x9d, - 0x1c, 0xcb, 0xd3, 0x8d, 0x2f, 0xd0, 0x54, 0xdd, 0x1e, 0xde, 0xaf, 0x38, 0x00, 0x35, 0xe5, 0xc0, - 0x26, 0x92, 0x5b, 0xa8, 0xad, 0xe2, 0x3a, 0xbb, 0x22, 0x56, 0x26, 0x46, 0x2a, 0xc7, 0x3e, 0x35, - 0x68, 0x9b, 0x9c, 0x0c, 0xf8, 0x4b, 0x93, 0x60, 0x57, 0xac, 0xec, 0x70, 0x9e, 0xf4, 0x12, 0x1e, - 0x9b, 0x43, 0x17, 0xd5, 0x94, 0x03, 0xbb, 0x5c, 0xd4, 0xfc, 0x17, 0x07, 0xc2, 0x55, 0x6b, 0x12, - 0x59, 0xfd, 0xbe, 0x00, 0x6c, 0x32, 0xed, 0xd8, 0xb8, 0xf3, 0x62, 0xbb, 0xc5, 0x62, 0x5b, 0x76, - 0xe1, 0x5c, 0x61, 0xc5, 0x5c, 0x07, 0x81, 0x33, 0xa2, 0x30, 0xb5, 0xd1, 0x68, 0xe0, 0x2e, 0x58, - 0x1e, 0xb6, 0xa3, 0xcb, 0xd9, 0x88, 0x7b, 0xad, 0x7d, 0x5c, 0x7d, 0xd5, 0x4d, 0x58, 0x75, 0x50, - 0xb1, 0x96, 0xb9, 0xd8, 0x3a, 0x63, 0xcd, 0x10, 0x7e, 0xb7, 0xcf, 0x19, 0x96, 0xf4, 0x7d, 0x10, - 0xf8, 0xbc, 0x83, 0xdb, 0x1d, 0xcd, 0xca, 0x36, 0x9c, 0xcd, 0x4e, 0xf7, 0xd1, 0x75, 0x32, 0xe0, - 0xa3, 0x14, 0x3f, 0xca, 0x5a, 0x64, 0x8c, 0xb0, 0x06, 0x82, 0x64, 0xaf, 0x8d, 0x8c, 0x3d, 0xdc, - 0xa4, 0x1b, 0x1d, 0x9e, 0x6a, 0xe8, 0x29, 0xfd, 0xe2, 0x90, 0xc2, 0xa1, 0x30, 0xe2, 0x85, 0x3d, - 0x0e, 0xcc, 0x9b, 0x27, 0x81, 0x3c, 0x92, 0xf2, 0x59, 0x52, 0xb5, 0xa9, 0xa5, 0xe2, 0x6e, 0x1e, - 0xd7, 0x3e, 0x5e, 0x64, 0xfb, 0xe8, 0xf2, 0x10, 0xc4, 0x88, 0x69, 0x90, 0x86, 0xef, 0x3f, 0x70, - 0x20, 0x76, 0xd6, 0x9e, 0xc0, 0xcb, 0x20, 0x32, 0xdc, 0x5e, 0x53, 0x92, 0x7d, 0x7a, 0x86, 0x6d, - 0xa3, 0xd4, 0x6d, 0xa1, 0xc9, 0x06, 0xf4, 0xfe, 0x77, 0x0d, 0x78, 0xf5, 0x4f, 0x0e, 0x00, 0xc7, - 0x47, 0xfc, 0x35, 0xb0, 0x5c, 0x2d, 0x49, 0x79, 0xb9, 0x54, 0x96, 0x0a, 0xa5, 0xa2, 0x7c, 0xb7, - 0x58, 0x29, 0xe7, 0x37, 0x0b, 0x5b, 0x85, 0x7c, 0x2e, 0xea, 0x49, 0x2c, 0xf4, 0xfa, 0xa9, 0x10, - 0x75, 0xcc, 0x9b, 0x32, 0x50, 0x00, 0x0b, 0x4e, 0xef, 0x7b, 0xf9, 0x4a, 0x94, 0x4b, 0x44, 0x7a, - 0xfd, 0x54, 0x90, 0x7a, 0xdd, 0x43, 0x06, 0xbc, 0x0a, 0x16, 0x9d, 0x3e, 0x99, 0x6c, 0x45, 0xca, - 0x14, 0x8a, 0x51, 0x6f, 0xe2, 0x42, 0xaf, 0x9f, 0x8a, 0x50, 0xbf, 0x0c, 0xbb, 0x71, 0x52, 0x60, - 0xde, 0xe9, 0x5b, 0x2c, 0x45, 0x7d, 0x89, 0x70, 0xaf, 0x9f, 0x9a, 0xa3, 0x6e, 0x45, 0x0c, 0xd7, - 0x41, 0xdc, 0xed, 0x21, 0x6f, 0x17, 0xa4, 0xdb, 0x72, 0x35, 0x2f, 0x95, 0xa2, 0xfe, 0x44, 0xac, - 0xd7, 0x4f, 0x45, 0x6d, 0x5f, 0xfb, 0x7a, 0x48, 0xf8, 0x1f, 0x7e, 0x93, 0xf4, 0x5c, 0xfd, 0xd9, - 0x0b, 0xe6, 0xdd, 0x5f, 0x90, 0x30, 0x0d, 0xfe, 0x57, 0x16, 0x4b, 0xe5, 0x52, 0x25, 0x73, 0x47, - 0xae, 0x48, 0x19, 0xe9, 0x6e, 0x65, 0x2c, 0x61, 0x2b, 0x15, 0xea, 0x5c, 0x54, 0x9b, 0xf0, 0x16, - 0x48, 0x8e, 0xfb, 0xe7, 0xf2, 0xe5, 0x52, 0xa5, 0x20, 0xc9, 0xe5, 0xbc, 0x58, 0x28, 0xe5, 0xa2, - 0x5c, 0x62, 0xb9, 0xd7, 0x4f, 0x2d, 0x52, 0x88, 0xeb, 0xdc, 0x81, 0xef, 0x81, 0xff, 0x8f, 0x83, - 0xab, 0x25, 0xa9, 0x50, 0xfc, 0xc8, 0xc6, 0x7a, 0x13, 0x4b, 0xbd, 0x7e, 0x0a, 0x52, 0xac, 0xab, - 0x8b, 0xae, 0x81, 0xa5, 0x71, 0x68, 0x39, 0x53, 0xa9, 0xe4, 0x73, 0x51, 0x5f, 0x22, 0xda, 0xeb, - 0xa7, 0xc2, 0x14, 0x53, 0x56, 0x0c, 0x03, 0xd5, 0xe1, 0x0d, 0x10, 0x1f, 0xf7, 0x16, 0xf3, 0x1f, - 0xe7, 0x37, 0xa5, 0x7c, 0x2e, 0xea, 0x4f, 0xc0, 0x5e, 0x3f, 0x35, 0x4f, 0xfd, 0x45, 0xf4, 0x29, - 0xaa, 0x11, 0x74, 0x26, 0xff, 0x56, 0xa6, 0x70, 0x27, 0x9f, 0x8b, 0xce, 0x38, 0xf9, 0xb7, 0x14, - 0xb5, 0x89, 0xea, 0xb4, 0x9c, 0xd9, 0xe2, 0xe1, 0x8b, 0xa4, 0xe7, 0xd9, 0x8b, 0xa4, 0xe7, 0xcb, - 0xa3, 0xa4, 0xe7, 0xf0, 0x28, 0xc9, 0x3d, 0x3d, 0x4a, 0x72, 0x7f, 0x1c, 0x25, 0xb9, 0x47, 0xc7, - 0x49, 0xcf, 0xd3, 0xe3, 0xa4, 0xe7, 0xd9, 0x71, 0xd2, 0x73, 0xff, 0xd5, 0x77, 0xc6, 0x81, 0xf5, - 0x0f, 0xd9, 0x1a, 0xc5, 0x9d, 0x80, 0xd5, 0xe5, 0x6f, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xc4, - 0x8b, 0xaf, 0xee, 0x3c, 0x0f, 0x00, 0x00, + // 1597 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0x1a, 0xd7, + 0x16, 0x67, 0x00, 0x7f, 0x70, 0x01, 0x9b, 0x5c, 0x63, 0x1b, 0xf3, 0x92, 0x19, 0x32, 0x79, 0x8a, + 0xac, 0x28, 0xc1, 0x89, 0xdf, 0xd3, 0x7b, 0x7a, 0x8e, 0xf4, 0xde, 0x03, 0x33, 0x7e, 0xe1, 0x29, + 0x02, 0x34, 0x10, 0xac, 0xe4, 0x2d, 0x46, 0x63, 0xb8, 0xc6, 0xf3, 0x0a, 0x73, 0x29, 0x73, 0x71, + 0x8c, 0xba, 0xc9, 0x32, 0x62, 0x51, 0x65, 0x99, 0xaa, 0x42, 0x8a, 0x5a, 0x75, 0xd3, 0x75, 0x17, + 0x5d, 0x75, 0x6d, 0x55, 0x95, 0x1a, 0x75, 0x15, 0x75, 0x41, 0x1a, 0x5b, 0xaa, 0x22, 0x2f, 0xfd, + 0x17, 0x54, 0x33, 0xf7, 0x0e, 0xcc, 0x00, 0x89, 0x43, 0x17, 0x5d, 0x79, 0xe6, 0x9c, 0xf3, 0xfb, + 0x9d, 0x8f, 0x7b, 0xce, 0xb9, 0x63, 0xc0, 0xe5, 0x0a, 0x36, 0x1a, 0xd8, 0xd8, 0xa8, 0xe1, 0xc3, + 0x8d, 0xc3, 0x3b, 0x7b, 0x88, 0xa8, 0x77, 0xcc, 0xe7, 0x64, 0xb3, 0x85, 0x09, 0x86, 0x90, 0x6a, + 0x93, 0xa6, 0x84, 0x69, 0xe3, 0x3c, 0x43, 0xec, 0xa9, 0x06, 0x1a, 0x40, 0x2a, 0x58, 0xd3, 0x29, + 0x26, 0x1e, 0xad, 0xe1, 0x1a, 0xb6, 0x1e, 0x37, 0xcc, 0x27, 0x26, 0x5d, 0xa3, 0x28, 0x85, 0x2a, + 0x18, 0x2d, 0x55, 0x09, 0x35, 0x8c, 0x6b, 0x75, 0xb4, 0x61, 0xbd, 0xed, 0xb5, 0xf7, 0x37, 0x88, + 0xd6, 0x40, 0x06, 0x51, 0x1b, 0x4d, 0x1b, 0x3b, 0x6a, 0xa0, 0xea, 0x1d, 0xa6, 0xe2, 0x47, 0x55, + 0xd5, 0x76, 0x4b, 0x25, 0x1a, 0x66, 0xc1, 0x88, 0x5f, 0x71, 0x00, 0xee, 0x22, 0xad, 0x76, 0x40, + 0x50, 0xb5, 0x8c, 0x09, 0xca, 0x37, 0x4d, 0x25, 0xfc, 0x1b, 0x98, 0xc5, 0xd6, 0x53, 0x8c, 0x4b, + 0x70, 0xeb, 0x0b, 0x9b, 0x7c, 0x72, 0x3c, 0xd1, 0xe4, 0xd0, 0x5e, 0x66, 0xd6, 0x70, 0x17, 0xcc, + 0x3e, 0xb6, 0xd8, 0x62, 0xde, 0x04, 0xb7, 0x1e, 0x48, 0xff, 0xeb, 0xb8, 0x2f, 0x78, 0x7e, 0xee, + 0x0b, 0xd7, 0x6b, 0x1a, 0x39, 0x68, 0xef, 0x25, 0x2b, 0xb8, 0xc1, 0x72, 0x63, 0x7f, 0x6e, 0x19, + 0xd5, 0x8f, 0x36, 0x48, 0xa7, 0x89, 0x8c, 0x64, 0x06, 0x55, 0xce, 0xfb, 0x42, 0xb8, 0xa3, 0x36, + 0xea, 0x5b, 0x22, 0x65, 0x11, 0x65, 0x46, 0x27, 0xee, 0x82, 0x50, 0x09, 0x1d, 0x91, 0x42, 0x0b, + 0x37, 0xb1, 0xa1, 0xd6, 0x61, 0x14, 0xcc, 0x10, 0x8d, 0xd4, 0x91, 0x15, 0x5f, 0x40, 0xa6, 0x2f, + 0x30, 0x01, 0x82, 0x55, 0x64, 0x54, 0x5a, 0x1a, 0x8d, 0xdd, 0x8a, 0x41, 0x76, 0x8a, 0xb6, 0x16, + 0xdf, 0xbe, 0x10, 0xb8, 0x9f, 0xbe, 0xb9, 0x35, 0xb7, 0x8d, 0x75, 0x82, 0x74, 0x22, 0xfe, 0xc8, + 0x81, 0xb9, 0x0c, 0x6a, 0x62, 0x43, 0x23, 0xf0, 0xef, 0x20, 0xd8, 0x64, 0x0e, 0x14, 0xad, 0x6a, + 0x51, 0xfb, 0xd3, 0x2b, 0xe7, 0x7d, 0x01, 0xd2, 0xa0, 0x1c, 0x4a, 0x51, 0x06, 0xf6, 0x5b, 0xb6, + 0x0a, 0x2f, 0x83, 0x40, 0x95, 0x72, 0xe0, 0x16, 0xf3, 0x3a, 0x14, 0xc0, 0x0a, 0x98, 0x55, 0x1b, + 0xb8, 0xad, 0x93, 0x98, 0x2f, 0xe1, 0x5b, 0x0f, 0x6e, 0xae, 0xd9, 0xc5, 0x34, 0x3b, 0x64, 0x50, + 0xcd, 0x6d, 0xac, 0xe9, 0xe9, 0xdb, 0x66, 0xbd, 0xbe, 0x7e, 0x2d, 0xac, 0x7f, 0x40, 0xbd, 0x4c, + 0x80, 0x21, 0x33, 0xea, 0xad, 0xf9, 0xa7, 0x2f, 0x04, 0xcf, 0xdb, 0x17, 0x82, 0x47, 0xfc, 0x6c, + 0x0e, 0xcc, 0x0f, 0xea, 0xf4, 0xd7, 0x49, 0x29, 0x2d, 0x9d, 0xf5, 0x05, 0xaf, 0x56, 0x3d, 0xef, + 0x0b, 0x01, 0x9a, 0xd8, 0x68, 0x3e, 0x77, 0xc1, 0x5c, 0x85, 0xd6, 0xc7, 0xca, 0x26, 0xb8, 0x19, + 0x4d, 0xd2, 0x3e, 0x4a, 0xda, 0x7d, 0x94, 0x4c, 0xe9, 0x9d, 0x74, 0xf0, 0xfb, 0x61, 0x21, 0x65, + 0x1b, 0x01, 0xcb, 0x60, 0xd6, 0x20, 0x2a, 0x69, 0x1b, 0x31, 0x9f, 0xd5, 0x3b, 0xe2, 0xa4, 0xde, + 0xb1, 0x03, 0x2c, 0x5a, 0x96, 0xe9, 0xf8, 0x79, 0x5f, 0x58, 0x19, 0x29, 0x32, 0x25, 0x11, 0x65, + 0xc6, 0x06, 0x9b, 0x00, 0xee, 0x6b, 0xba, 0x5a, 0x57, 0x88, 0x5a, 0xaf, 0x77, 0x94, 0x16, 0x32, + 0xda, 0x75, 0x12, 0xf3, 0x5b, 0xf1, 0x09, 0x93, 0x7c, 0x94, 0x4c, 0x3b, 0xd9, 0x32, 0x4b, 0x5f, + 0x35, 0x0b, 0x7b, 0xde, 0x17, 0xd6, 0xa8, 0x93, 0x71, 0x22, 0x51, 0x8e, 0x58, 0x42, 0x07, 0x08, + 0xfe, 0x0f, 0x04, 0x8d, 0xf6, 0x5e, 0x43, 0x23, 0x8a, 0x39, 0x71, 0xb1, 0x19, 0xcb, 0x55, 0x7c, + 0xac, 0x14, 0x25, 0x7b, 0x1c, 0xd3, 0x3c, 0xf3, 0xc2, 0xfa, 0xc5, 0x01, 0x16, 0x9f, 0xbd, 0x16, + 0x38, 0x19, 0x50, 0x89, 0x09, 0x80, 0x1a, 0x88, 0xb0, 0x16, 0x51, 0x90, 0x5e, 0xa5, 0x1e, 0x66, + 0x2f, 0xf4, 0x70, 0x8d, 0x79, 0x58, 0xa5, 0x1e, 0x46, 0x19, 0xa8, 0x9b, 0x05, 0x26, 0x96, 0xf4, + 0xaa, 0xe5, 0xea, 0x29, 0x07, 0xc2, 0x04, 0x13, 0xb5, 0xae, 0x30, 0x45, 0x6c, 0xee, 0xa2, 0x46, + 0xbc, 0xc7, 0xfc, 0x44, 0xa9, 0x1f, 0x17, 0x5a, 0x9c, 0xaa, 0x41, 0x43, 0x16, 0xd6, 0x1e, 0xb1, + 0x3a, 0xb8, 0x74, 0x88, 0x89, 0xa6, 0xd7, 0xcc, 0xe3, 0x6d, 0xb1, 0xc2, 0xce, 0x5f, 0x98, 0xf6, + 0x9f, 0x59, 0x38, 0x31, 0x1a, 0xce, 0x18, 0x05, 0xcd, 0x7b, 0x91, 0xca, 0x8b, 0xa6, 0xd8, 0x4a, + 0x7c, 0x1f, 0x30, 0xd1, 0xb0, 0xc4, 0x81, 0x0b, 0x7d, 0x89, 0xcc, 0xd7, 0x8a, 0xcb, 0x97, 0xbb, + 0xc2, 0x61, 0x2a, 0xb5, 0x0b, 0x7c, 0x15, 0x84, 0x34, 0x43, 0x41, 0x47, 0x4d, 0x54, 0xd5, 0x08, + 0xaa, 0xc6, 0x40, 0x82, 0x5b, 0x9f, 0x97, 0x83, 0x9a, 0x21, 0xd9, 0xa2, 0x2d, 0xbf, 0xb9, 0x78, + 0xc4, 0x63, 0x2f, 0x08, 0x3a, 0x3b, 0xec, 0xdf, 0xc0, 0xd7, 0x41, 0x06, 0x5d, 0x62, 0xe9, 0xe4, + 0x14, 0xcb, 0x32, 0xab, 0x13, 0xd9, 0x84, 0xc2, 0x7b, 0x60, 0x4e, 0xdd, 0x33, 0x88, 0xaa, 0xb1, + 0x75, 0x37, 0x35, 0x8b, 0x0d, 0x87, 0xff, 0x04, 0x5e, 0x1d, 0x5b, 0x33, 0x3b, 0x3d, 0x89, 0x57, + 0xc7, 0xb0, 0x06, 0x42, 0x3a, 0x56, 0x1e, 0x6b, 0xe4, 0x40, 0x39, 0x44, 0x04, 0x5b, 0x93, 0x19, + 0x48, 0x4b, 0xd3, 0x31, 0x9d, 0xf7, 0x85, 0x25, 0x5a, 0x77, 0x27, 0x97, 0x28, 0x03, 0x1d, 0xef, + 0x6a, 0xe4, 0xa0, 0x8c, 0x08, 0x66, 0xa5, 0x3c, 0xe5, 0x80, 0xdf, 0xbc, 0x81, 0x7e, 0xff, 0xd6, + 0x8e, 0x82, 0x99, 0x43, 0x4c, 0x90, 0xbd, 0xb1, 0xe9, 0x0b, 0xdc, 0x1a, 0x5c, 0x7d, 0xbe, 0x0f, + 0xb9, 0xfa, 0xd2, 0xde, 0x18, 0x37, 0xb8, 0xfe, 0x76, 0xc0, 0x1c, 0x7d, 0x32, 0x62, 0x7e, 0x6b, + 0xc2, 0xae, 0x4f, 0x02, 0x8f, 0xdf, 0xb7, 0x69, 0xbf, 0x59, 0x25, 0xd9, 0x06, 0x6f, 0xcd, 0x3f, + 0xb7, 0x97, 0xf9, 0x77, 0x5e, 0x10, 0x66, 0xb3, 0x53, 0x50, 0x5b, 0x6a, 0xc3, 0x80, 0x9f, 0x73, + 0x20, 0xd8, 0xd0, 0xf4, 0xc1, 0x28, 0x73, 0x17, 0x8d, 0xb2, 0x62, 0x72, 0x9f, 0xf5, 0x85, 0x65, + 0x07, 0xea, 0x26, 0x6e, 0x68, 0x04, 0x35, 0x9a, 0xa4, 0x33, 0xac, 0x93, 0x43, 0x3d, 0xdd, 0x84, + 0x83, 0x86, 0xa6, 0xdb, 0xf3, 0xfd, 0x29, 0x07, 0x60, 0x43, 0x3d, 0xb2, 0x89, 0x94, 0x26, 0x6a, + 0x69, 0xb8, 0xca, 0x6e, 0x91, 0xb5, 0xb1, 0xa9, 0xcb, 0xb0, 0xaf, 0x11, 0xda, 0x26, 0x67, 0x7d, + 0xe1, 0xf2, 0x38, 0xd8, 0x15, 0x2b, 0xdb, 0xdf, 0xe3, 0x56, 0xe2, 0x73, 0x73, 0x2e, 0x23, 0x0d, + 0xf5, 0xc8, 0x2e, 0x17, 0x13, 0xfb, 0x40, 0xa8, 0x6c, 0x0d, 0x2b, 0xab, 0xdf, 0x27, 0x80, 0x0d, + 0xaf, 0x1d, 0x1b, 0x77, 0x51, 0x6c, 0x77, 0x59, 0x6c, 0xab, 0x2e, 0x9c, 0x2b, 0xac, 0xa8, 0x6b, + 0x57, 0x38, 0x23, 0x0a, 0x51, 0x19, 0x8d, 0x06, 0xee, 0x83, 0xd5, 0x41, 0x3b, 0xba, 0x8c, 0x8d, + 0x98, 0xd7, 0x3a, 0xc7, 0xf5, 0xf7, 0x5d, 0x96, 0x65, 0x07, 0x15, 0x6b, 0x99, 0xe5, 0xe6, 0x04, + 0x9d, 0x01, 0xbf, 0xe0, 0xc0, 0xea, 0x60, 0x1d, 0xb9, 0x3d, 0x59, 0x6d, 0xfd, 0xde, 0x7c, 0xf3, + 0x2c, 0xdf, 0xab, 0xef, 0x60, 0x70, 0x65, 0xce, 0xd3, 0xcc, 0xdf, 0x61, 0x4a, 0x6b, 0xb0, 0x3c, + 0xd0, 0x3a, 0xa3, 0x14, 0xfb, 0x3e, 0xb6, 0x0c, 0xd9, 0xc9, 0x3c, 0x02, 0xb3, 0x1f, 0xb7, 0x71, + 0xab, 0xdd, 0xb0, 0x8e, 0x24, 0x94, 0x4e, 0x4f, 0xf7, 0xf1, 0x78, 0xd6, 0x17, 0x22, 0x14, 0x3f, + 0x0c, 0x50, 0x66, 0x8c, 0xb0, 0x02, 0x02, 0xe4, 0xa0, 0x85, 0x8c, 0x03, 0x5c, 0xa7, 0xdd, 0x18, + 0x9a, 0x6a, 0x33, 0x51, 0xfa, 0xa5, 0x01, 0x85, 0xc3, 0xc3, 0x90, 0x17, 0x76, 0x39, 0xb0, 0x60, + 0xae, 0x2b, 0x65, 0xe8, 0xca, 0x67, 0xb9, 0xaa, 0x4c, 0xed, 0x2a, 0xe6, 0xe6, 0x71, 0x95, 0x7c, + 0x99, 0x35, 0x9b, 0xcb, 0x42, 0x94, 0xc3, 0xa6, 0xa0, 0x34, 0x08, 0xe6, 0x09, 0x07, 0x96, 0x86, + 0xa7, 0x32, 0x8c, 0xc8, 0x6f, 0x45, 0x94, 0x9f, 0x3a, 0xa2, 0x2b, 0x13, 0xc8, 0x1c, 0x65, 0x80, + 0x03, 0xf5, 0x20, 0x04, 0xf1, 0x5b, 0x0e, 0x44, 0x27, 0xf5, 0x2e, 0xbc, 0x06, 0xc2, 0x83, 0x31, + 0x30, 0x7d, 0xb0, 0xaf, 0xf8, 0x90, 0x2d, 0x2c, 0x75, 0x9a, 0x68, 0x7c, 0x50, 0xbd, 0x7f, 0xdc, + 0xa0, 0xde, 0xf8, 0x95, 0x03, 0xc0, 0xf1, 0xff, 0xd0, 0x4d, 0xb0, 0x5a, 0xce, 0x97, 0x24, 0x25, + 0x5f, 0x28, 0x65, 0xf3, 0x39, 0xe5, 0x41, 0xae, 0x58, 0x90, 0xb6, 0xb3, 0x3b, 0x59, 0x29, 0x13, + 0xf1, 0xc4, 0x17, 0xbb, 0xbd, 0x44, 0x90, 0x1a, 0x4a, 0xa6, 0x1b, 0x28, 0x82, 0x45, 0xa7, 0xf5, + 0x43, 0xa9, 0x18, 0xe1, 0xe2, 0xe1, 0x6e, 0x2f, 0x11, 0xa0, 0x56, 0x0f, 0x91, 0x01, 0x6f, 0x80, + 0x25, 0xa7, 0x4d, 0x2a, 0x5d, 0x2c, 0xa5, 0xb2, 0xb9, 0x88, 0x37, 0x7e, 0xa9, 0xdb, 0x4b, 0x84, + 0xa9, 0x5d, 0x8a, 0xdd, 0xcc, 0x09, 0xb0, 0xe0, 0xb4, 0xcd, 0xe5, 0x23, 0xbe, 0x78, 0xa8, 0xdb, + 0x4b, 0xcc, 0x53, 0xb3, 0x1c, 0x86, 0x9b, 0x20, 0xe6, 0xb6, 0x50, 0x76, 0xb3, 0xa5, 0x7b, 0x4a, + 0x59, 0x2a, 0xe5, 0x23, 0xfe, 0x78, 0xb4, 0xdb, 0x4b, 0x44, 0x6c, 0x5b, 0xfb, 0x1a, 0x8d, 0xfb, + 0x9f, 0x7e, 0xc9, 0x7b, 0x6e, 0xfc, 0xe0, 0x05, 0x0b, 0xee, 0x8f, 0x71, 0x98, 0x04, 0x7f, 0x2a, + 0xc8, 0xf9, 0x42, 0xbe, 0x98, 0xba, 0xaf, 0x14, 0x4b, 0xa9, 0xd2, 0x83, 0xe2, 0x48, 0xc2, 0x56, + 0x2a, 0xd4, 0x38, 0xa7, 0xd5, 0xe1, 0x5d, 0xc0, 0x8f, 0xda, 0x67, 0xa4, 0x42, 0xbe, 0x98, 0x2d, + 0x29, 0x05, 0x49, 0xce, 0xe6, 0x33, 0x11, 0x2e, 0xbe, 0xda, 0xed, 0x25, 0x96, 0x28, 0xc4, 0xb5, + 0x9f, 0xe1, 0x3f, 0xc0, 0x95, 0x51, 0x70, 0x39, 0x5f, 0xca, 0xe6, 0xfe, 0x63, 0x63, 0xbd, 0xf1, + 0x95, 0x6e, 0x2f, 0x01, 0x29, 0xd6, 0xd5, 0x45, 0x37, 0xc1, 0xca, 0x28, 0xb4, 0x90, 0x2a, 0x16, + 0xa5, 0x4c, 0xc4, 0x17, 0x8f, 0x74, 0x7b, 0x89, 0x10, 0xc5, 0x14, 0x54, 0xc3, 0x40, 0x55, 0x78, + 0x1b, 0xc4, 0x46, 0xad, 0x65, 0xe9, 0xbf, 0xd2, 0x76, 0x49, 0xca, 0x44, 0xfc, 0x71, 0xd8, 0xed, + 0x25, 0x16, 0xa8, 0xbd, 0x8c, 0xfe, 0x8f, 0x2a, 0x04, 0x4d, 0xe4, 0xdf, 0x49, 0x65, 0xef, 0x4b, + 0x99, 0xc8, 0x8c, 0x93, 0x7f, 0x47, 0xd5, 0xea, 0xa8, 0x4a, 0xcb, 0x99, 0xce, 0x1d, 0xbf, 0xe1, + 0x3d, 0xaf, 0xde, 0xf0, 0x9e, 0x27, 0x27, 0xbc, 0xe7, 0xf8, 0x84, 0xe7, 0x5e, 0x9e, 0xf0, 0xdc, + 0x2f, 0x27, 0x3c, 0xf7, 0xec, 0x94, 0xf7, 0xbc, 0x3c, 0xe5, 0x3d, 0xaf, 0x4e, 0x79, 0xcf, 0xa3, + 0xf7, 0xdf, 0xad, 0x47, 0xd6, 0x8f, 0x0d, 0xd6, 0xec, 0xed, 0xcd, 0x5a, 0x5d, 0xfe, 0x97, 0xdf, + 0x02, 0x00, 0x00, 0xff, 0xff, 0x88, 0x57, 0xc4, 0xb1, 0x87, 0x10, 0x00, 0x00, } func (this *TextProposal) Equal(that interface{}) bool { @@ -728,6 +738,9 @@ func (this *Proposal) Equal(that interface{}) bool { if !this.VotingEndTime.Equal(that1.VotingEndTime) { return false } + if this.IsExpedited != that1.IsExpedited { + return false + } return true } func (this *TallyResult) Equal(that interface{}) bool { @@ -907,6 +920,16 @@ func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.IsExpedited { + i-- + if m.IsExpedited { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + } n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingEndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime):]) if err1 != nil { return 0, err1 @@ -1170,6 +1193,14 @@ func (m *VotingParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + n8, err8 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.ExpeditedVotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.ExpeditedVotingPeriod):]) + if err8 != nil { + return 0, err8 + } + i -= n8 + i = encodeVarintGov(dAtA, i, uint64(n8)) + i-- + dAtA[i] = 0x1a if len(m.ProposalVotingPeriods) > 0 { for iNdEx := len(m.ProposalVotingPeriods) - 1; iNdEx >= 0; iNdEx-- { { @@ -1184,12 +1215,12 @@ func (m *VotingParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } } - n8, err8 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod):]) - if err8 != nil { - return 0, err8 + n9, err9 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod):]) + if err9 != nil { + return 0, err9 } - i -= n8 - i = encodeVarintGov(dAtA, i, uint64(n8)) + i -= n9 + i = encodeVarintGov(dAtA, i, uint64(n9)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil @@ -1215,6 +1246,16 @@ func (m *TallyParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.ExpeditedThreshold.Size() + i -= size + if _, err := m.ExpeditedThreshold.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGov(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 { size := m.VetoThreshold.Size() i -= size @@ -1268,12 +1309,12 @@ func (m *ProposalVotingPeriod) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n9, err9 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod):]) - if err9 != nil { - return 0, err9 + n10, err10 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod):]) + if err10 != nil { + return 0, err10 } - i -= n9 - i = encodeVarintGov(dAtA, i, uint64(n9)) + i -= n10 + i = encodeVarintGov(dAtA, i, uint64(n10)) i-- dAtA[i] = 0x12 if len(m.ProposalType) > 0 { @@ -1382,6 +1423,9 @@ func (m *Proposal) Size() (n int) { n += 1 + l + sovGov(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingEndTime) n += 1 + l + sovGov(uint64(l)) + if m.IsExpedited { + n += 2 + } return n } @@ -1458,6 +1502,8 @@ func (m *VotingParams) Size() (n int) { n += 1 + l + sovGov(uint64(l)) } } + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.ExpeditedVotingPeriod) + n += 1 + l + sovGov(uint64(l)) return n } @@ -1473,6 +1519,8 @@ func (m *TallyParams) Size() (n int) { n += 1 + l + sovGov(uint64(l)) l = m.VetoThreshold.Size() n += 1 + l + sovGov(uint64(l)) + l = m.ExpeditedThreshold.Size() + n += 1 + l + sovGov(uint64(l)) return n } @@ -2151,6 +2199,26 @@ func (m *Proposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsExpedited", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsExpedited = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGov(dAtA[iNdEx:]) @@ -2725,6 +2793,39 @@ func (m *VotingParams) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpeditedVotingPeriod", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.ExpeditedVotingPeriod, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGov(dAtA[iNdEx:]) @@ -2874,6 +2975,39 @@ func (m *TallyParams) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpeditedThreshold", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ExpeditedThreshold.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGov(dAtA[iNdEx:]) diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index 7f58d8fdfbac..fefa0d621266 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -62,7 +62,7 @@ func GetProposalIDFromBytes(bz []byte) (proposalID uint64) { return binary.BigEndian.Uint64(bz) } -// ProposalKey gets a specific proposal from the store +// ProposalKey returns a store prefix for a proposal with proposalId. func ProposalKey(proposalID uint64) []byte { return append(ProposalsKeyPrefix, GetProposalIDBytes(proposalID)...) } diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index f1c351e6ddca..276eb4a0ff0c 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -27,10 +27,11 @@ var ( // NewMsgSubmitProposal creates a new MsgSubmitProposal. //nolint:interfacer -func NewMsgSubmitProposal(content Content, initialDeposit sdk.Coins, proposer sdk.AccAddress) (*MsgSubmitProposal, error) { +func NewMsgSubmitProposal(content Content, initialDeposit sdk.Coins, proposer sdk.AccAddress, isExpedited bool) (*MsgSubmitProposal, error) { m := &MsgSubmitProposal{ InitialDeposit: initialDeposit, Proposer: proposer.String(), + IsExpedited: isExpedited, } err := m.SetContent(content) if err != nil { diff --git a/x/gov/types/msgs_test.go b/x/gov/types/msgs_test.go index 2a8fd5275895..d616a8807550 100644 --- a/x/gov/types/msgs_test.go +++ b/x/gov/types/msgs_test.go @@ -27,19 +27,20 @@ func init() { func TestMsgSubmitProposal(t *testing.T) { tests := []struct { title, description string + isExpedited bool proposalType string proposerAddr sdk.AccAddress initialDeposit sdk.Coins expectPass bool }{ - {"Test Proposal", "the purpose of this proposal is to test", ProposalTypeText, addrs[0], coinsPos, true}, - {"", "the purpose of this proposal is to test", ProposalTypeText, addrs[0], coinsPos, false}, - {"Test Proposal", "", ProposalTypeText, addrs[0], coinsPos, false}, - {"Test Proposal", "the purpose of this proposal is to test", ProposalTypeText, sdk.AccAddress{}, coinsPos, false}, - {"Test Proposal", "the purpose of this proposal is to test", ProposalTypeText, addrs[0], coinsZero, true}, - {"Test Proposal", "the purpose of this proposal is to test", ProposalTypeText, addrs[0], coinsMulti, true}, - {strings.Repeat("#", MaxTitleLength*2), "the purpose of this proposal is to test", ProposalTypeText, addrs[0], coinsMulti, false}, - {"Test Proposal", strings.Repeat("#", MaxDescriptionLength*2), ProposalTypeText, addrs[0], coinsMulti, false}, + {"Test Proposal", "the purpose of this proposal is to test", true, ProposalTypeText, addrs[0], coinsPos, true}, + {"", "the purpose of this proposal is to test", false, ProposalTypeText, addrs[0], coinsPos, false}, + {"Test Proposal", "", true, ProposalTypeText, addrs[0], coinsPos, false}, + {"Test Proposal", "the purpose of this proposal is to test", false, ProposalTypeText, sdk.AccAddress{}, coinsPos, false}, + {"Test Proposal", "the purpose of this proposal is to test", true, ProposalTypeText, addrs[0], coinsZero, true}, + {"Test Proposal", "the purpose of this proposal is to test", false, ProposalTypeText, addrs[0], coinsMulti, true}, + {strings.Repeat("#", MaxTitleLength*2), "the purpose of this proposal is to test", true, ProposalTypeText, addrs[0], coinsMulti, false}, + {"Test Proposal", strings.Repeat("#", MaxDescriptionLength*2), true, ProposalTypeText, addrs[0], coinsMulti, false}, } for i, tc := range tests { @@ -47,6 +48,7 @@ func TestMsgSubmitProposal(t *testing.T) { ContentFromProposalType(tc.title, tc.description, tc.proposalType), tc.initialDeposit, tc.proposerAddr, + tc.isExpedited, ) require.NoError(t, err) @@ -164,7 +166,7 @@ func TestMsgVoteWeighted(t *testing.T) { // this tests that Amino JSON MsgSubmitProposal.GetSignBytes() still works with Content as Any using the ModuleCdc func TestMsgSubmitProposal_GetSignBytes(t *testing.T) { - msg, err := NewMsgSubmitProposal(NewTextProposal("test", "abcd"), sdk.NewCoins(), sdk.AccAddress{}) + msg, err := NewMsgSubmitProposal(NewTextProposal("test", "abcd"), sdk.NewCoins(), sdk.AccAddress{}, false) require.NoError(t, err) var bz []byte require.NotPanics(t, func() { diff --git a/x/gov/types/params.go b/x/gov/types/params.go index b0b66075feae..0a80e7e141c7 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -15,15 +15,19 @@ import ( // Default period for deposits & voting const ( - DefaultPeriod time.Duration = time.Hour * 24 * 2 // 2 days + DefaultPeriod time.Duration = time.Hour * 24 * 2 // 2 days + DefaultExpeditedPeriod time.Duration = time.Hour * 24 // 1 day ) // Default governance params var ( - DefaultMinDepositTokens = sdk.NewInt(10000000) - DefaultQuorum = sdk.NewDecWithPrec(334, 3) - DefaultThreshold = sdk.NewDecWithPrec(5, 1) - DefaultVetoThreshold = sdk.NewDecWithPrec(334, 3) + DefaultMinDepositTokens = sdk.NewInt(10000000) + DefaultQuorum = sdk.NewDecWithPrec(334, 3) + DefaultThreshold = sdk.NewDecWithPrec(5, 1) + DefaultExpeditedThreshold = sdk.NewDecWithPrec(667, 3) + DefaultVetoThreshold = sdk.NewDecWithPrec(334, 3) + + DefaultProposalVotingPeriods []ProposalVotingPeriod = []ProposalVotingPeriod{} ) // Parameter store key @@ -86,22 +90,31 @@ func validateDepositParams(i interface{}) error { } // NewTallyParams creates a new TallyParams object -func NewTallyParams(quorum, threshold, vetoThreshold sdk.Dec) TallyParams { +func NewTallyParams(quorum, threshold, expeditedThreshold, vetoThreshold sdk.Dec) TallyParams { return TallyParams{ - Quorum: quorum, - Threshold: threshold, - VetoThreshold: vetoThreshold, + Quorum: quorum, + Threshold: threshold, + ExpeditedThreshold: expeditedThreshold, + VetoThreshold: vetoThreshold, } } // DefaultTallyParams default parameters for tallying func DefaultTallyParams() TallyParams { - return NewTallyParams(DefaultQuorum, DefaultThreshold, DefaultVetoThreshold) + return NewTallyParams(DefaultQuorum, DefaultThreshold, DefaultExpeditedThreshold, DefaultVetoThreshold) +} + +// GetThreshold returns threshold based on the value isExpedited +func (tp TallyParams) GetThreshold(isExpedited bool) sdk.Dec { + if isExpedited { + return tp.ExpeditedThreshold + } + return tp.Threshold } // Equal checks equality of TallyParams func (tp TallyParams) Equal(other TallyParams) bool { - return tp.Quorum.Equal(other.Quorum) && tp.Threshold.Equal(other.Threshold) && tp.VetoThreshold.Equal(other.VetoThreshold) + return tp.Quorum.Equal(other.Quorum) && tp.Threshold.Equal(other.Threshold) && tp.ExpeditedThreshold.Equal(other.ExpeditedThreshold) && tp.VetoThreshold.Equal(other.VetoThreshold) } // String implements stringer insterface @@ -126,7 +139,16 @@ func validateTallyParams(i interface{}) error { return fmt.Errorf("vote threshold must be positive: %s", v.Threshold) } if v.Threshold.GT(sdk.OneDec()) { - return fmt.Errorf("vote threshold too large: %s", v) + return fmt.Errorf("vote threshold too large: %s", v.Threshold) + } + if !v.ExpeditedThreshold.IsPositive() { + return fmt.Errorf("expedited ote threshold must be positive: %s", v.ExpeditedThreshold) + } + if v.ExpeditedThreshold.GT(sdk.OneDec()) { + return fmt.Errorf("expedited vote threshold too large: %s", v.ExpeditedThreshold) + } + if v.ExpeditedThreshold.LTE(v.Threshold) { + return fmt.Errorf("expedited vote threshold %s, must be greater than the regular threshold %s", v.ExpeditedThreshold, v.Threshold) } if !v.VetoThreshold.IsPositive() { return fmt.Errorf("veto threshold must be positive: %s", v.Threshold) @@ -139,16 +161,25 @@ func validateTallyParams(i interface{}) error { } // NewVotingParams creates a new VotingParams object -func NewVotingParams(votingPeriod time.Duration, pvps []ProposalVotingPeriod) VotingParams { +func NewVotingParams(votingPeriod time.Duration, expeditedPeriod time.Duration, pvps []ProposalVotingPeriod) VotingParams { return VotingParams{ VotingPeriod: votingPeriod, + ExpeditedVotingPeriod: expeditedPeriod, ProposalVotingPeriods: pvps, } } // DefaultVotingParams default parameters for voting func DefaultVotingParams() VotingParams { - return NewVotingParams(DefaultPeriod, []ProposalVotingPeriod{}) + return NewVotingParams(DefaultPeriod, DefaultExpeditedPeriod, []ProposalVotingPeriod{}) +} + +// GetVotingPeriod returns voting period based on whether isExpedited is requested. +func (vp VotingParams) GetVotingPeriod(isExpedited bool) time.Duration { + if isExpedited { + return vp.ExpeditedVotingPeriod + } + return vp.VotingPeriod } // Equal checks equality of TallyParams @@ -173,6 +204,14 @@ func validateVotingParams(i interface{}) error { return fmt.Errorf("voting period must be positive: %s", v.VotingPeriod) } + if v.ExpeditedVotingPeriod <= 0 { + return fmt.Errorf("expedited voting period must be positive: %s", v.ExpeditedVotingPeriod) + } + + if v.ExpeditedVotingPeriod >= v.VotingPeriod { + return fmt.Errorf("expedited voting period %s must be strictly less that the regular voting period %s", v.ExpeditedVotingPeriod, v.VotingPeriod) + } + for _, pvp := range v.ProposalVotingPeriods { if pvp.ProposalType == "" { return errors.New("empty proposal type for proposal voting period") diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index f7d5d9d4dd93..57611fb1e74c 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -17,7 +17,7 @@ import ( const DefaultStartingProposalID uint64 = 1 // NewProposal creates a new Proposal instance -func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Time) (Proposal, error) { +func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Time, isExpedited bool) (Proposal, error) { msg, ok := content.(proto.Message) if !ok { return Proposal{}, fmt.Errorf("%T does not implement proto.Message", content) @@ -36,6 +36,7 @@ func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Tim TotalDeposit: sdk.NewCoins(), SubmitTime: submitTime, DepositEndTime: depositEndTime, + IsExpedited: isExpedited, } return p, nil diff --git a/x/gov/types/tx.pb.go b/x/gov/types/tx.pb.go index 63a3660d49b3..5ca7e1af8c63 100644 --- a/x/gov/types/tx.pb.go +++ b/x/gov/types/tx.pb.go @@ -38,6 +38,7 @@ type MsgSubmitProposal struct { Content *types.Any `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` InitialDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=initial_deposit,json=initialDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"initial_deposit" yaml:"initial_deposit"` Proposer string `protobuf:"bytes,3,opt,name=proposer,proto3" json:"proposer,omitempty"` + IsExpedited bool `protobuf:"varint,4,opt,name=is_expedited,json=isExpedited,proto3" json:"is_expedited,omitempty"` } func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } @@ -363,49 +364,50 @@ func init() { func init() { proto.RegisterFile("cosmos/gov/v1beta1/tx.proto", fileDescriptor_3c053992595e3dce) } var fileDescriptor_3c053992595e3dce = []byte{ - // 659 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x3f, 0x6f, 0xd3, 0x5e, - 0x14, 0xb5, 0x93, 0xfe, 0x9a, 0x5f, 0x5f, 0x50, 0x4b, 0x9f, 0xa2, 0x92, 0xb8, 0x95, 0x1d, 0x19, - 0xb5, 0x8a, 0x84, 0x6a, 0xd3, 0x20, 0x81, 0x54, 0x26, 0x52, 0x54, 0x01, 0x52, 0x04, 0x18, 0x09, - 0x24, 0x96, 0xe2, 0x24, 0xae, 0x6b, 0x91, 0xf8, 0x5a, 0x79, 0x2f, 0x51, 0xb3, 0x31, 0x32, 0x01, - 0x23, 0x63, 0x67, 0x36, 0x24, 0x26, 0x3e, 0x41, 0xc5, 0xd4, 0x91, 0x01, 0x05, 0xd4, 0x2e, 0x80, - 0x98, 0xfa, 0x09, 0x90, 0xdf, 0x1f, 0xb7, 0x34, 0x6e, 0x54, 0x50, 0xa7, 0xe4, 0xdd, 0x73, 0xcf, - 0xf1, 0x3d, 0xf7, 0xdd, 0x6b, 0xa3, 0xf9, 0x26, 0x90, 0x0e, 0x10, 0xdb, 0x87, 0xbe, 0xdd, 0x5f, - 0x69, 0x78, 0xd4, 0x5d, 0xb1, 0xe9, 0xb6, 0x15, 0x75, 0x81, 0x02, 0xc6, 0x1c, 0xb4, 0x7c, 0xe8, - 0x5b, 0x02, 0xd4, 0x74, 0x41, 0x68, 0xb8, 0xc4, 0x4b, 0x18, 0x4d, 0x08, 0x42, 0xce, 0xd1, 0x16, - 0x52, 0x04, 0x63, 0x3e, 0x47, 0x4b, 0x1c, 0xdd, 0x60, 0x27, 0x5b, 0xc8, 0x73, 0xa8, 0xe0, 0x83, - 0x0f, 0x3c, 0x1e, 0xff, 0x93, 0x04, 0x1f, 0xc0, 0x6f, 0x7b, 0x36, 0x3b, 0x35, 0x7a, 0x9b, 0xb6, - 0x1b, 0x0e, 0x38, 0x64, 0xbe, 0xce, 0xa0, 0xd9, 0x3a, 0xf1, 0x1f, 0xf5, 0x1a, 0x9d, 0x80, 0x3e, - 0xe8, 0x42, 0x04, 0xc4, 0x6d, 0xe3, 0x9b, 0x28, 0xd7, 0x84, 0x90, 0x7a, 0x21, 0x2d, 0xaa, 0x65, - 0xb5, 0x92, 0xaf, 0x16, 0x2c, 0x2e, 0x61, 0x49, 0x09, 0xeb, 0x56, 0x38, 0xa8, 0xe5, 0x3f, 0x7d, - 0x58, 0xce, 0xad, 0xf1, 0x44, 0x47, 0x32, 0xf0, 0x2b, 0x15, 0xcd, 0x04, 0x61, 0x40, 0x03, 0xb7, - 0xbd, 0xd1, 0xf2, 0x22, 0x20, 0x01, 0x2d, 0x66, 0xca, 0xd9, 0x4a, 0xbe, 0x5a, 0xb2, 0x44, 0xb1, - 0xb1, 0x6f, 0xd9, 0x0c, 0x6b, 0x0d, 0x82, 0xb0, 0x76, 0x6f, 0x77, 0x68, 0x28, 0x87, 0x43, 0x63, - 0x6e, 0xe0, 0x76, 0xda, 0xab, 0xe6, 0x09, 0xbe, 0xf9, 0xee, 0xab, 0x51, 0xf1, 0x03, 0xba, 0xd5, - 0x6b, 0x58, 0x4d, 0xe8, 0x08, 0xcf, 0xe2, 0x67, 0x99, 0xb4, 0x9e, 0xdb, 0x74, 0x10, 0x79, 0x84, - 0x49, 0x11, 0x67, 0x5a, 0xb0, 0x6f, 0x73, 0x32, 0xd6, 0xd0, 0xff, 0x11, 0x73, 0xe6, 0x75, 0x8b, - 0xd9, 0xb2, 0x5a, 0x99, 0x72, 0x92, 0xf3, 0xea, 0xc5, 0x97, 0x3b, 0x86, 0xf2, 0x76, 0xc7, 0x50, - 0xbe, 0xef, 0x18, 0xca, 0x8b, 0x2f, 0x65, 0xc5, 0x6c, 0xa2, 0xd2, 0x48, 0x43, 0x1c, 0x8f, 0x44, - 0x10, 0x12, 0x0f, 0xaf, 0xa3, 0x7c, 0x24, 0x62, 0x1b, 0x41, 0x8b, 0x35, 0x67, 0xa2, 0xb6, 0xf8, - 0x73, 0x68, 0x1c, 0x0f, 0x1f, 0x0e, 0x0d, 0xcc, 0x6d, 0x1c, 0x0b, 0x9a, 0x0e, 0x92, 0xa7, 0xbb, - 0x2d, 0xf3, 0xbd, 0x8a, 0x72, 0x75, 0xe2, 0x3f, 0x06, 0x7a, 0x6e, 0x9a, 0xb8, 0x80, 0xfe, 0xeb, - 0x03, 0xf5, 0xba, 0xc5, 0x0c, 0xf3, 0xc8, 0x0f, 0xf8, 0x3a, 0x9a, 0x84, 0x88, 0x06, 0x10, 0x32, - 0xeb, 0xd3, 0x55, 0xdd, 0x1a, 0x9d, 0x47, 0x2b, 0xae, 0xe3, 0x3e, 0xcb, 0x72, 0x44, 0x76, 0x4a, - 0x63, 0x66, 0xd1, 0x8c, 0x28, 0x59, 0xb6, 0xc3, 0xfc, 0xa8, 0x26, 0xb1, 0x27, 0x5e, 0xe0, 0x6f, - 0x51, 0xaf, 0x85, 0x6f, 0xa4, 0xd9, 0x99, 0xfb, 0xe7, 0xfa, 0xd7, 0x51, 0x8e, 0x57, 0x44, 0x8a, - 0x59, 0x36, 0x44, 0x4b, 0x69, 0x06, 0xe4, 0xd3, 0x8f, 0x8c, 0xd4, 0x26, 0xe2, 0x89, 0x72, 0x24, - 0x39, 0xc5, 0x4f, 0x09, 0x5d, 0x3a, 0x51, 0x7b, 0xe2, 0xeb, 0x87, 0x8a, 0x50, 0x9d, 0xf8, 0x72, - 0x80, 0xce, 0xeb, 0x86, 0x16, 0xd0, 0x94, 0x18, 0x68, 0x90, 0x2e, 0x8f, 0x02, 0xb8, 0x89, 0x26, - 0xdd, 0x0e, 0xf4, 0x42, 0x2a, 0x8c, 0x8e, 0xd9, 0x96, 0xab, 0xb1, 0xb7, 0xbf, 0xda, 0x09, 0x21, - 0x9d, 0xd2, 0x86, 0x02, 0xc2, 0x47, 0x56, 0x65, 0x07, 0xaa, 0xbf, 0x32, 0x28, 0x5b, 0x27, 0x3e, - 0xde, 0x44, 0xd3, 0x27, 0xde, 0x0d, 0x8b, 0x69, 0xfd, 0x1f, 0xd9, 0x18, 0x6d, 0xf9, 0x4c, 0x69, - 0xc9, 0x62, 0xdd, 0x41, 0x13, 0x6c, 0x19, 0xe6, 0x4f, 0xa1, 0xc5, 0xa0, 0x76, 0x79, 0x0c, 0x98, - 0x28, 0x3d, 0x43, 0x17, 0xfe, 0x98, 0xc7, 0x71, 0x24, 0x99, 0xa4, 0x5d, 0x39, 0x43, 0x52, 0xf2, - 0x84, 0x87, 0x28, 0x27, 0x27, 0x43, 0x3f, 0x85, 0x27, 0x70, 0x6d, 0x69, 0x3c, 0x2e, 0x25, 0x6b, - 0xb5, 0xdd, 0x7d, 0x5d, 0xdd, 0xdb, 0xd7, 0xd5, 0x6f, 0xfb, 0xba, 0xfa, 0xe6, 0x40, 0x57, 0xf6, - 0x0e, 0x74, 0xe5, 0xf3, 0x81, 0xae, 0x3c, 0x1d, 0x7f, 0xc5, 0xdb, 0xec, 0x13, 0xc1, 0x2e, 0xba, - 0x31, 0xc9, 0xde, 0xcd, 0xd7, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x96, 0x26, 0x77, 0x3f, 0x8e, - 0x06, 0x00, 0x00, + // 685 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x41, 0x6f, 0xd3, 0x48, + 0x14, 0xb6, 0x93, 0x6c, 0xd3, 0x4e, 0xaa, 0x76, 0x3b, 0x8a, 0xba, 0x89, 0x5b, 0xd9, 0x59, 0xaf, + 0x5a, 0x45, 0x5a, 0xd5, 0xa6, 0x41, 0x02, 0xa9, 0x9c, 0x48, 0xa1, 0x02, 0xa4, 0x08, 0x30, 0x12, + 0x48, 0x5c, 0x82, 0x13, 0x4f, 0xdd, 0x11, 0x89, 0xc7, 0xca, 0x4c, 0xa2, 0xe6, 0xc6, 0x91, 0x13, + 0xe2, 0xc8, 0xb1, 0x67, 0x6e, 0x20, 0x4e, 0xfc, 0x82, 0x8a, 0x53, 0x8f, 0x1c, 0x50, 0x40, 0xed, + 0x05, 0x10, 0xa7, 0xfe, 0x02, 0x64, 0xcf, 0x8c, 0x5b, 0x5a, 0x37, 0x2a, 0xa8, 0xa7, 0x64, 0xde, + 0xf7, 0xbe, 0xe7, 0xf7, 0x7d, 0xf3, 0x9e, 0x0d, 0x16, 0xda, 0x84, 0x76, 0x09, 0xb5, 0x7d, 0x32, + 0xb0, 0x07, 0xab, 0x2d, 0xc4, 0xdc, 0x55, 0x9b, 0x6d, 0x5b, 0x61, 0x8f, 0x30, 0x02, 0x21, 0x07, + 0x2d, 0x9f, 0x0c, 0x2c, 0x01, 0x6a, 0xba, 0x20, 0xb4, 0x5c, 0x8a, 0x12, 0x46, 0x9b, 0xe0, 0x80, + 0x73, 0xb4, 0xc5, 0x94, 0x82, 0x11, 0x9f, 0xa3, 0x65, 0x8e, 0x36, 0xe3, 0x93, 0x2d, 0xca, 0x73, + 0xa8, 0xe8, 0x13, 0x9f, 0xf0, 0x78, 0xf4, 0x4f, 0x12, 0x7c, 0x42, 0xfc, 0x0e, 0xb2, 0xe3, 0x53, + 0xab, 0xbf, 0x69, 0xbb, 0xc1, 0x90, 0x43, 0xe6, 0xdb, 0x0c, 0x98, 0x6b, 0x50, 0xff, 0x41, 0xbf, + 0xd5, 0xc5, 0xec, 0x5e, 0x8f, 0x84, 0x84, 0xba, 0x1d, 0x78, 0x0d, 0xe4, 0xdb, 0x24, 0x60, 0x28, + 0x60, 0x25, 0xb5, 0xa2, 0x56, 0x0b, 0xb5, 0xa2, 0xc5, 0x4b, 0x58, 0xb2, 0x84, 0x75, 0x3d, 0x18, + 0xd6, 0x0b, 0x1f, 0xde, 0xad, 0xe4, 0xd7, 0x79, 0xa2, 0x23, 0x19, 0xf0, 0x85, 0x0a, 0x66, 0x71, + 0x80, 0x19, 0x76, 0x3b, 0x4d, 0x0f, 0x85, 0x84, 0x62, 0x56, 0xca, 0x54, 0xb2, 0xd5, 0x42, 0xad, + 0x6c, 0x89, 0x66, 0x23, 0xdd, 0xd2, 0x0c, 0x6b, 0x9d, 0xe0, 0xa0, 0x7e, 0x67, 0x77, 0x64, 0x28, + 0x87, 0x23, 0x63, 0x7e, 0xe8, 0x76, 0x3b, 0x6b, 0xe6, 0x09, 0xbe, 0xf9, 0xfa, 0xb3, 0x51, 0xf5, + 0x31, 0xdb, 0xea, 0xb7, 0xac, 0x36, 0xe9, 0x0a, 0xcd, 0xe2, 0x67, 0x85, 0x7a, 0x4f, 0x6d, 0x36, + 0x0c, 0x11, 0x8d, 0x4b, 0x51, 0x67, 0x46, 0xb0, 0x6f, 0x70, 0x32, 0xd4, 0xc0, 0x64, 0x18, 0x2b, + 0x43, 0xbd, 0x52, 0xb6, 0xa2, 0x56, 0xa7, 0x9c, 0xe4, 0x0c, 0xff, 0x05, 0xd3, 0x98, 0x36, 0xd1, + 0x76, 0x88, 0x3c, 0xcc, 0x90, 0x57, 0xca, 0x55, 0xd4, 0xea, 0xa4, 0x53, 0xc0, 0xf4, 0xa6, 0x0c, + 0xad, 0xfd, 0xfd, 0x7c, 0xc7, 0x50, 0x5e, 0xed, 0x18, 0xca, 0xd7, 0x1d, 0x43, 0x79, 0xf6, 0xa9, + 0xa2, 0x98, 0x6d, 0x50, 0x3e, 0xe5, 0x99, 0x83, 0x68, 0x48, 0x02, 0x8a, 0xe0, 0x06, 0x28, 0x84, + 0x22, 0xd6, 0xc4, 0x5e, 0xec, 0x5f, 0xae, 0xbe, 0xf4, 0x7d, 0x64, 0x1c, 0x0f, 0x1f, 0x8e, 0x0c, + 0xc8, 0x95, 0x1e, 0x0b, 0x9a, 0x0e, 0x90, 0xa7, 0xdb, 0x9e, 0xf9, 0x46, 0x05, 0xf9, 0x06, 0xf5, + 0x1f, 0x12, 0x76, 0x61, 0x35, 0x61, 0x11, 0xfc, 0x35, 0x20, 0x0c, 0xf5, 0x4a, 0x99, 0xd8, 0x06, + 0x7e, 0x80, 0x57, 0xc0, 0x04, 0x09, 0x19, 0x26, 0x41, 0xec, 0xce, 0x4c, 0x4d, 0xb7, 0x4e, 0x8f, + 0xac, 0x15, 0xf5, 0x71, 0x37, 0xce, 0x72, 0x44, 0x76, 0x8a, 0x31, 0x73, 0x60, 0x56, 0xb4, 0x2c, + 0xed, 0x30, 0xdf, 0xab, 0x49, 0xec, 0x11, 0xc2, 0xfe, 0x16, 0x43, 0x1e, 0xbc, 0x9a, 0x26, 0x67, + 0xfe, 0x8f, 0xfb, 0xdf, 0x00, 0x79, 0xde, 0x11, 0x2d, 0x65, 0xe3, 0x39, 0x5b, 0x4e, 0x13, 0x20, + 0x9f, 0x7e, 0x24, 0xa4, 0x9e, 0x8b, 0x86, 0xce, 0x91, 0xe4, 0x14, 0x3d, 0x65, 0xf0, 0xcf, 0x89, + 0xde, 0x13, 0x5d, 0xdf, 0x54, 0x00, 0x1a, 0xd4, 0x97, 0x33, 0x76, 0x51, 0x37, 0xb4, 0x08, 0xa6, + 0xc4, 0xcc, 0x13, 0xa9, 0xf2, 0x28, 0x00, 0xdb, 0x60, 0xc2, 0xed, 0x92, 0x7e, 0xc0, 0x84, 0xd0, + 0x31, 0x0b, 0x75, 0x29, 0xd2, 0xf6, 0x5b, 0x6b, 0x23, 0x4a, 0xa7, 0xd8, 0x50, 0x04, 0xf0, 0x48, + 0xaa, 0x74, 0xa0, 0xf6, 0x23, 0x03, 0xb2, 0x0d, 0xea, 0xc3, 0x4d, 0x30, 0x73, 0xe2, 0xf5, 0xb1, + 0x94, 0xe6, 0xff, 0xa9, 0x8d, 0xd1, 0x56, 0xce, 0x95, 0x96, 0x2c, 0xd6, 0x2d, 0x90, 0x8b, 0x97, + 0x61, 0xe1, 0x0c, 0x5a, 0x04, 0x6a, 0xff, 0x8d, 0x01, 0x93, 0x4a, 0x4f, 0xc0, 0xf4, 0x2f, 0xf3, + 0x38, 0x8e, 0x24, 0x93, 0xb4, 0xff, 0xcf, 0x91, 0x94, 0x3c, 0xe1, 0x3e, 0xc8, 0xcb, 0xc9, 0xd0, + 0xcf, 0xe0, 0x09, 0x5c, 0x5b, 0x1e, 0x8f, 0xcb, 0x92, 0xf5, 0xfa, 0xee, 0xbe, 0xae, 0xee, 0xed, + 0xeb, 0xea, 0x97, 0x7d, 0x5d, 0x7d, 0x79, 0xa0, 0x2b, 0x7b, 0x07, 0xba, 0xf2, 0xf1, 0x40, 0x57, + 0x1e, 0x8f, 0xbf, 0xe2, 0xed, 0xf8, 0x2b, 0x12, 0x5f, 0x74, 0x6b, 0x22, 0x7e, 0x7d, 0x5f, 0xfe, + 0x19, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x36, 0x6a, 0xce, 0xb1, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -628,6 +630,16 @@ func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.IsExpedited { + i-- + if m.IsExpedited { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } if len(m.Proposer) > 0 { i -= len(m.Proposer) copy(dAtA[i:], m.Proposer) @@ -930,6 +942,9 @@ func (m *MsgSubmitProposal) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if m.IsExpedited { + n += 2 + } return n } @@ -1172,6 +1187,26 @@ func (m *MsgSubmitProposal) Unmarshal(dAtA []byte) error { } m.Proposer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsExpedited", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsExpedited = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index 9c263a2c2b27..a26f8ed1faf1 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -15,10 +15,12 @@ import ( paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) +const flagIsExpedited = "is-expedited" + // NewSubmitParamChangeProposalTxCmd returns a CLI command handler for creating // a parameter change proposal governance transaction. func NewSubmitParamChangeProposalTxCmd() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "param-change [proposal-file]", Args: cobra.ExactArgs(1), Short: "Submit a parameter change proposal", @@ -36,7 +38,7 @@ Proper vetting of a parameter change proposal should prevent this from happening regardless. Example: -$ %s tx gov submit-proposal param-change --from= +$ %s tx gov submit-proposal param-change --from= --is-expedited=true Where proposal.json contains: @@ -68,7 +70,7 @@ Where proposal.json contains: from := clientCtx.GetFromAddress() content := paramproposal.NewParameterChangeProposal( - proposal.Title, proposal.Description, proposal.Changes.ToParamChanges(), + proposal.Title, proposal.Description, proposal.IsExpedited, proposal.Changes.ToParamChanges(), ) deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) @@ -76,7 +78,12 @@ Where proposal.json contains: return err } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + isExpedited, err := cmd.Flags().GetBool(flagIsExpedited) + if err != nil { + return err + } + + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from, isExpedited) if err != nil { return err } @@ -84,4 +91,8 @@ Where proposal.json contains: return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } + + cmd.Flags().Bool(flagIsExpedited, false, "If true, makes the proposal an expedited one") + + return cmd } diff --git a/x/params/client/rest/rest.go b/x/params/client/rest/rest.go index 70d90236e05f..75619c8e6188 100644 --- a/x/params/client/rest/rest.go +++ b/x/params/client/rest/rest.go @@ -33,9 +33,9 @@ func postProposalHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - content := proposal.NewParameterChangeProposal(req.Title, req.Description, req.Changes.ToParamChanges()) + content := proposal.NewParameterChangeProposal(req.Title, req.Description, req.IsExpedited, req.Changes.ToParamChanges()) - msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) + msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer, req.IsExpedited) if rest.CheckBadRequestError(w, err) { return } diff --git a/x/params/client/utils/utils.go b/x/params/client/utils/utils.go index b4c680fdde24..c504a1f8f247 100644 --- a/x/params/client/utils/utils.go +++ b/x/params/client/utils/utils.go @@ -28,6 +28,7 @@ type ( ParamChangeProposalJSON struct { Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` + IsExpedited bool `json:"is_expedited" yaml:"is_expedited"` Changes ParamChangesJSON `json:"changes" yaml:"changes"` Deposit string `json:"deposit" yaml:"deposit"` } @@ -38,6 +39,7 @@ type ( Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` + IsExpedited bool `json:"is_expedited" yaml:"is_expedited"` Changes ParamChangesJSON `json:"changes" yaml:"changes"` Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` Deposit sdk.Coins `json:"deposit" yaml:"deposit"` diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index b5c79669a66d..f48b6ca3a3d5 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -34,7 +34,7 @@ func TestHandlerTestSuite(t *testing.T) { } func testProposal(changes ...proposal.ParamChange) *proposal.ParameterChangeProposal { - return proposal.NewParameterChangeProposal("title", "description", changes) + return proposal.NewParameterChangeProposal("title", "description", false, changes) } func (suite *HandlerTestSuite) TestProposalHandler() { diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index 6e7619b7032b..bfdc8ec1c957 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -43,10 +43,12 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange title := fmt.Sprintf("title from SimulateParamChangeProposalContent-%d", numProposals) desc := fmt.Sprintf("desc from SimulateParamChangeProposalContent-%d. Random short desc: %s", numProposals, simulation.RandStringOfLength(r, 20)) + isExpedited := r.Intn(2) == 0 numProposals++ return proposal.NewParameterChangeProposal( title, // title desc, // description + isExpedited, // flag indicating whether the proposal is expedited paramChanges, // set of changes ) } diff --git a/x/params/types/proposal/proposal.go b/x/params/types/proposal/proposal.go index 3a2f97a77247..a0df1bace01f 100644 --- a/x/params/types/proposal/proposal.go +++ b/x/params/types/proposal/proposal.go @@ -22,7 +22,7 @@ func init() { govtypes.RegisterProposalTypeCodec(&ParameterChangeProposal{}, "cosmos-sdk/ParameterChangeProposal") } -func NewParameterChangeProposal(title, description string, changes []ParamChange) *ParameterChangeProposal { +func NewParameterChangeProposal(title, description string, isExpedited bool, changes []ParamChange) *ParameterChangeProposal { return &ParameterChangeProposal{title, description, changes} } diff --git a/x/params/types/proposal/proposal_test.go b/x/params/types/proposal/proposal_test.go index a18f9c407609..bb727b06803f 100644 --- a/x/params/types/proposal/proposal_test.go +++ b/x/params/types/proposal/proposal_test.go @@ -7,9 +7,11 @@ import ( ) func TestParameterChangeProposal(t *testing.T) { + const isExpedited = true + pc1 := NewParamChange("sub", "foo", "baz") pc2 := NewParamChange("sub", "bar", "cat") - pcp := NewParameterChangeProposal("test title", "test description", []ParamChange{pc1, pc2}) + pcp := NewParameterChangeProposal("test title", "test description", isExpedited, []ParamChange{pc1, pc2}) require.Equal(t, "test title", pcp.GetTitle()) require.Equal(t, "test description", pcp.GetDescription()) @@ -18,10 +20,10 @@ func TestParameterChangeProposal(t *testing.T) { require.Nil(t, pcp.ValidateBasic()) pc3 := NewParamChange("", "bar", "cat") - pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc3}) + pcp = NewParameterChangeProposal("test title", "test description", isExpedited, []ParamChange{pc3}) require.Error(t, pcp.ValidateBasic()) pc4 := NewParamChange("sub", "", "cat") - pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc4}) + pcp = NewParameterChangeProposal("test title", "test description", isExpedited, []ParamChange{pc4}) require.Error(t, pcp.ValidateBasic()) } diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index 3d793cbab693..7d53b4f2a328 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -57,7 +57,12 @@ func NewCmdSubmitUpgradeProposal() *cobra.Command { return err } - msg, err := gov.NewMsgSubmitProposal(content, deposit, from) + isExpedited, err := cmd.Flags().GetBool(cli.FlagIsExpedited) + if err != nil { + return err + } + + msg, err := gov.NewMsgSubmitProposal(content, deposit, from, isExpedited) if err != nil { return err } @@ -69,6 +74,7 @@ func NewCmdSubmitUpgradeProposal() *cobra.Command { cmd.Flags().String(cli.FlagTitle, "", "title of proposal") cmd.Flags().String(cli.FlagDescription, "", "description of proposal") cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") + cmd.Flags().Bool(cli.FlagIsExpedited, false, "flag indicating whether a proposal is expedited") cmd.Flags().Int64(FlagUpgradeHeight, 0, "The height at which the upgrade must happen") cmd.Flags().String(FlagUpgradeInfo, "", "Optional info for the planned upgrade such as commit hash, etc.") @@ -109,9 +115,14 @@ func NewCmdSubmitCancelUpgradeProposal() *cobra.Command { return err } + isExpedited, err := cmd.Flags().GetBool(cli.FlagIsExpedited) + if err != nil { + return err + } + content := types.NewCancelSoftwareUpgradeProposal(title, description) - msg, err := gov.NewMsgSubmitProposal(content, deposit, from) + msg, err := gov.NewMsgSubmitProposal(content, deposit, from, isExpedited) if err != nil { return err } @@ -123,6 +134,7 @@ func NewCmdSubmitCancelUpgradeProposal() *cobra.Command { cmd.Flags().String(cli.FlagTitle, "", "title of proposal") cmd.Flags().String(cli.FlagDescription, "", "description of proposal") cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") + cmd.Flags().Bool(cli.FlagIsExpedited, false, "flag indicating whether a proposal is expedited") cmd.MarkFlagRequired(cli.FlagTitle) cmd.MarkFlagRequired(cli.FlagDescription) diff --git a/x/upgrade/client/rest/tx.go b/x/upgrade/client/rest/tx.go index 131173fa2ac9..b0a2d4a9f81d 100644 --- a/x/upgrade/client/rest/tx.go +++ b/x/upgrade/client/rest/tx.go @@ -28,6 +28,7 @@ type PlanRequest struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` + IsExpedited bool `json:"is_expedited" yaml:"is_expedited"` Deposit sdk.Coins `json:"deposit" yaml:"deposit"` UpgradeName string `json:"upgrade_name" yaml:"upgrade_name"` UpgradeHeight int64 `json:"upgrade_height" yaml:"upgrade_height"` @@ -39,6 +40,7 @@ type CancelRequest struct { BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` Title string `json:"title" yaml:"title"` Description string `json:"description" yaml:"description"` + IsExpedited bool `json:"is_expedited" yaml:"is_expedited"` Deposit sdk.Coins `json:"deposit" yaml:"deposit"` } @@ -76,7 +78,7 @@ func newPostPlanHandler(clientCtx client.Context) http.HandlerFunc { plan := types.Plan{Name: req.UpgradeName, Height: req.UpgradeHeight, Info: req.UpgradeInfo} content := types.NewSoftwareUpgradeProposal(req.Title, req.Description, plan) - msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, fromAddr) + msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, fromAddr, req.IsExpedited) if rest.CheckBadRequestError(w, err) { return } @@ -108,7 +110,7 @@ func newCancelPlanHandler(clientCtx client.Context) http.HandlerFunc { content := types.NewCancelSoftwareUpgradeProposal(req.Title, req.Description) - msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, fromAddr) + msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, fromAddr, req.IsExpedited) if rest.CheckBadRequestError(w, err) { return }