From 379239eb9b238375f77920d7574ceedab673979c Mon Sep 17 00:00:00 2001 From: John Letey Date: Wed, 15 Jun 2022 12:53:49 +0100 Subject: [PATCH 1/6] feat: custom proposal-based voting periods (#1) h/t osmosis-labs/cosmos-sdk#239 --- docs/core/proto-docs.md | 21 +- proto/cosmos/gov/v1beta1/gov.proto | 17 +- x/gov/client/testutil/cli_test.go | 3 +- x/gov/client/testutil/suite.go | 5 +- x/gov/keeper/grpc_query_test.go | 2 +- x/gov/keeper/params.go | 5 + x/gov/keeper/proposal.go | 32 +- x/gov/legacy/v040/migrate_test.go | 1 + x/gov/legacy/v043/json_test.go | 1 + x/gov/simulation/genesis.go | 17 +- x/gov/types/gov.pb.go | 454 +++++++++++++++++++++++------ x/gov/types/params.go | 56 +++- 12 files changed, 508 insertions(+), 106 deletions(-) diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 407163322e43..9eae4ea48463 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -347,6 +347,7 @@ - [Deposit](#cosmos.gov.v1beta1.Deposit) - [DepositParams](#cosmos.gov.v1beta1.DepositParams) - [Proposal](#cosmos.gov.v1beta1.Proposal) + - [ProposalVotingPeriod](#cosmos.gov.v1beta1.ProposalVotingPeriod) - [TallyParams](#cosmos.gov.v1beta1.TallyParams) - [TallyResult](#cosmos.gov.v1beta1.TallyResult) - [TextProposal](#cosmos.gov.v1beta1.TextProposal) @@ -5115,6 +5116,23 @@ Proposal defines the core field members of a governance proposal. + + +### ProposalVotingPeriod +ProposalVotingPeriod defines custom voting periods for a unique governance +proposal type. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `proposal_type` | [string](#string) | | e.g. "cosmos.params.v1beta1.ParameterChangeProposal" | +| `voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | | + + + + + + ### TallyParams @@ -5194,7 +5212,8 @@ VotingParams defines the params for voting on governance proposals. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | Length of the voting period. | +| `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. | diff --git a/proto/cosmos/gov/v1beta1/gov.proto b/proto/cosmos/gov/v1beta1/gov.proto index 01aebf950cf3..56dff2566ec1 100644 --- a/proto/cosmos/gov/v1beta1/gov.proto +++ b/proto/cosmos/gov/v1beta1/gov.proto @@ -163,13 +163,16 @@ message DepositParams { // VotingParams defines the params for voting on governance proposals. message VotingParams { - // Length of the voting period. + // voting_period defines the length of the voting period. google.protobuf.Duration voting_period = 1 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.jsontag) = "voting_period,omitempty", (gogoproto.moretags) = "yaml:\"voting_period\"" ]; + + // proposal_voting_periods defines custom voting periods for proposal types. + repeated ProposalVotingPeriod proposal_voting_periods = 2 [(gogoproto.nullable) = false]; } // TallyParams defines the params for tallying votes on governance proposals. @@ -198,3 +201,15 @@ message TallyParams { (gogoproto.moretags) = "yaml:\"veto_threshold\"" ]; } + +// ProposalVotingPeriod defines custom voting periods for a unique governance +// proposal type. +message ProposalVotingPeriod { + string proposal_type = 1; // e.g. "cosmos.params.v1beta1.ParameterChangeProposal" + google.protobuf.Duration voting_period = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "voting_period,omitempty", + (gogoproto.moretags) = "yaml:\"voting_period\"" + ]; +} diff --git a/x/gov/client/testutil/cli_test.go b/x/gov/client/testutil/cli_test.go index 713c33f12182..6870df4b653b 100644 --- a/x/gov/client/testutil/cli_test.go +++ b/x/gov/client/testutil/cli_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package testutil @@ -21,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) + genesisState.VotingParams = types.NewVotingParams(time.Duration(5)*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 ee2634e3d188..de55c3e20184 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"},"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},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`, }, { "text output", @@ -104,6 +104,7 @@ tally_params: threshold: "0.500000000000000000" veto_threshold: "0.334000000000000000" voting_params: + proposal_voting_periods: null voting_period: "172800000000000" `, }, @@ -137,7 +138,7 @@ func (s *IntegrationTestSuite) TestCmdParam() { "voting", fmt.Sprintf("--%s=json", tmcli.OutputFlag), }, - `{"voting_period":"172800000000000"}`, + `{"voting_period":"172800000000000","proposal_voting_periods":null}`, }, { "tally params", diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index 0e7d6f251091..fd9cb255d92e 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -505,7 +505,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() { if testCase.expPass { suite.Require().NoError(err) suite.Require().Equal(expRes.GetDepositParams(), params.GetDepositParams()) - suite.Require().Equal(expRes.GetVotingParams(), params.GetVotingParams()) + suite.Require().True(expRes.GetVotingParams().Equal(params.GetVotingParams())) suite.Require().Equal(expRes.GetTallyParams(), params.GetTallyParams()) } else { suite.Require().Error(err) diff --git a/x/gov/keeper/params.go b/x/gov/keeper/params.go index 0c6fc4338b9f..52eb83dc9f31 100644 --- a/x/gov/keeper/params.go +++ b/x/gov/keeper/params.go @@ -16,6 +16,11 @@ func (keeper Keeper) GetDepositParams(ctx sdk.Context) types.DepositParams { func (keeper Keeper) GetVotingParams(ctx sdk.Context) types.VotingParams { var votingParams types.VotingParams keeper.paramSpace.Get(ctx, types.ParamStoreKeyVotingParams, &votingParams) + + if votingParams.ProposalVotingPeriods == nil { + votingParams.ProposalVotingPeriods = []types.ProposalVotingPeriod{} + } + return votingParams } diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 216596932fad..e9d870815246 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -2,6 +2,9 @@ package keeper import ( "fmt" + "github.com/gogo/protobuf/proto" + "strings" + "time" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" @@ -183,17 +186,42 @@ func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) { store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID)) } +// ActivateVotingPeriod moves the governance proposal from the deposit stage to +// the voting stage, given that enough deposits have been submitted. It is +// removed from the inactive proposal queue and moved into the active queue. +// Note, if the proposal's contents has a custom voting period registered, that +// 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 - votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod - proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) proposal.Status = types.StatusVotingPeriod + + votingPeriod := keeper.GetVotingPeriod(ctx, proposal.GetContent()) + proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) + keeper.SetProposal(ctx, proposal) keeper.RemoveFromInactiveProposalQueue(ctx, proposal.ProposalId, proposal.DepositEndTime) keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) } +// GetVotingPeriod returns the voting period for the given proposal Content. If +// the proposal type has a custom voting period registered, we return that. +// Otherwise, we use the default voting period. +func (keeper Keeper) GetVotingPeriod(ctx sdk.Context, content types.Content) time.Duration { + vpParams := keeper.GetVotingParams(ctx) + + // Check if there exists a registered custom voting period for the proposal + // type. + for _, pvp := range vpParams.ProposalVotingPeriods { + contentProto, ok := content.(proto.Message) + if ok && strings.EqualFold(pvp.ProposalType, proto.MessageName(contentProto)) { + return pvp.VotingPeriod + } + } + + return vpParams.VotingPeriod +} + func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) { bz, err := keeper.cdc.Marshal(&proposal) if err != nil { diff --git a/x/gov/legacy/v040/migrate_test.go b/x/gov/legacy/v040/migrate_test.go index 664696bf296e..cb47240973b9 100644 --- a/x/gov/legacy/v040/migrate_test.go +++ b/x/gov/legacy/v040/migrate_test.go @@ -231,6 +231,7 @@ func TestMigrate(t *testing.T) { }, "votes": [], "voting_params": { + "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 d9f045774661..39504a3cce36 100644 --- a/x/gov/legacy/v043/json_test.go +++ b/x/gov/legacy/v043/json_test.go @@ -118,6 +118,7 @@ func TestMigrateJSON(t *testing.T) { } ], "voting_params": { + "proposal_voting_periods": [], "voting_period": "0s" } }` diff --git a/x/gov/simulation/genesis.go b/x/gov/simulation/genesis.go index 3f9ed2d086a7..ad7451294e58 100644 --- a/x/gov/simulation/genesis.go +++ b/x/gov/simulation/genesis.go @@ -94,10 +94,25 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { veto = GenTallyParamsVeto(r) }, ) + proposalVotingPeriods := []types.ProposalVotingPeriod{ + { + ProposalType: "cosmos.params.v1beta1.ParameterChangeProposal", + }, + } + for _, pvp := range proposalVotingPeriods { + var pvpDuration time.Duration + simState.AppParams.GetOrGenerate( + simState.Cdc, VotingParamsVotingPeriod, &pvpDuration, simState.Rand, + func(r *rand.Rand) { pvpDuration = GenVotingParamsVotingPeriod(r) }, + ) + + pvp.VotingPeriod = pvpDuration + } + govGenesis := types.NewGenesisState( startingProposalID, types.NewDepositParams(minDeposit, depositPeriod), - types.NewVotingParams(votingPeriod), + types.NewVotingParams(votingPeriod, proposalVotingPeriods), types.NewTallyParams(quorum, threshold, veto), ) diff --git a/x/gov/types/gov.pb.go b/x/gov/types/gov.pb.go index cc46f20a9c54..6cccc4e0e0ea 100644 --- a/x/gov/types/gov.pb.go +++ b/x/gov/types/gov.pb.go @@ -413,8 +413,10 @@ var xxx_messageInfo_DepositParams proto.InternalMessageInfo // VotingParams defines the params for voting on governance proposals. type VotingParams struct { - // Length of the voting period. + // voting_period defines the length of the voting period. 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"` } func (m *VotingParams) Reset() { *m = VotingParams{} } @@ -493,6 +495,45 @@ func (m *TallyParams) XXX_DiscardUnknown() { var xxx_messageInfo_TallyParams proto.InternalMessageInfo +// ProposalVotingPeriod defines custom voting periods for a unique governance +// proposal type. +type ProposalVotingPeriod struct { + ProposalType string `protobuf:"bytes,1,opt,name=proposal_type,json=proposalType,proto3" json:"proposal_type,omitempty"` + VotingPeriod time.Duration `protobuf:"bytes,2,opt,name=voting_period,json=votingPeriod,proto3,stdduration" json:"voting_period,omitempty" yaml:"voting_period"` +} + +func (m *ProposalVotingPeriod) Reset() { *m = ProposalVotingPeriod{} } +func (*ProposalVotingPeriod) ProtoMessage() {} +func (*ProposalVotingPeriod) Descriptor() ([]byte, []int) { + return fileDescriptor_6e82113c1a9a4b7c, []int{9} +} +func (m *ProposalVotingPeriod) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProposalVotingPeriod) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProposalVotingPeriod.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ProposalVotingPeriod) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProposalVotingPeriod.Merge(m, src) +} +func (m *ProposalVotingPeriod) XXX_Size() int { + return m.Size() +} +func (m *ProposalVotingPeriod) XXX_DiscardUnknown() { + xxx_messageInfo_ProposalVotingPeriod.DiscardUnknown(m) +} + +var xxx_messageInfo_ProposalVotingPeriod proto.InternalMessageInfo + func init() { proto.RegisterEnum("cosmos.gov.v1beta1.VoteOption", VoteOption_name, VoteOption_value) proto.RegisterEnum("cosmos.gov.v1beta1.ProposalStatus", ProposalStatus_name, ProposalStatus_value) @@ -505,103 +546,108 @@ func init() { proto.RegisterType((*DepositParams)(nil), "cosmos.gov.v1beta1.DepositParams") proto.RegisterType((*VotingParams)(nil), "cosmos.gov.v1beta1.VotingParams") proto.RegisterType((*TallyParams)(nil), "cosmos.gov.v1beta1.TallyParams") + proto.RegisterType((*ProposalVotingPeriod)(nil), "cosmos.gov.v1beta1.ProposalVotingPeriod") } func init() { proto.RegisterFile("cosmos/gov/v1beta1/gov.proto", fileDescriptor_6e82113c1a9a4b7c) } var fileDescriptor_6e82113c1a9a4b7c = []byte{ - // 1454 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x51, 0x68, 0xdb, 0x56, - 0x17, 0xb6, 0x6c, 0xc7, 0x89, 0xaf, 0x9d, 0x44, 0xbd, 0x49, 0x13, 0xc7, 0x7f, 0x7f, 0xc9, 0xbf, - 0xfe, 0x9f, 0x12, 0x4a, 0xeb, 0xb4, 0xf9, 0xc7, 0xc6, 0x52, 0xd8, 0x66, 0xc5, 0xca, 0xea, 0x51, - 0x6c, 0x23, 0xab, 0x0e, 0xed, 0x1e, 0x84, 0x62, 0xdf, 0x3a, 0xda, 0x2c, 0x5d, 0xcf, 0xba, 0x4e, - 0x13, 0xf6, 0xb2, 0xc7, 0xe2, 0xc1, 0xe8, 0x63, 0x61, 0x18, 0x0a, 0x63, 0x2f, 0x7b, 0xde, 0xf3, - 0x9e, 0xc3, 0x18, 0xac, 0xec, 0xa9, 0x6c, 0xe0, 0xae, 0x09, 0x8c, 0x92, 0xc7, 0x3c, 0xec, 0x79, - 0x48, 0xf7, 0x2a, 0x96, 0xed, 0xb0, 0xd4, 0x7b, 0x8a, 0x74, 0xee, 0xf9, 0xbe, 0x73, 0xce, 0xe7, - 0x73, 0xce, 0x55, 0xc0, 0x95, 0x1a, 0x76, 0x2c, 0xec, 0xac, 0x35, 0xf0, 0xde, 0xda, 0xde, 0xad, - 0x1d, 0x44, 0x8c, 0x5b, 0xee, 0x73, 0xb6, 0xd5, 0xc6, 0x04, 0x43, 0x48, 0x4f, 0xb3, 0xae, 0x85, - 0x9d, 0xa6, 0x05, 0x86, 0xd8, 0x31, 0x1c, 0x74, 0x06, 0xa9, 0x61, 0xd3, 0xa6, 0x98, 0xf4, 0x62, - 0x03, 0x37, 0xb0, 0xf7, 0xb8, 0xe6, 0x3e, 0x31, 0xeb, 0x0a, 0x45, 0xe9, 0xf4, 0x80, 0xd1, 0xd2, - 0x23, 0xb1, 0x81, 0x71, 0xa3, 0x89, 0xd6, 0xbc, 0xb7, 0x9d, 0xce, 0xc3, 0x35, 0x62, 0x5a, 0xc8, - 0x21, 0x86, 0xd5, 0xf2, 0xb1, 0xa3, 0x0e, 0x86, 0x7d, 0xc0, 0x8e, 0x84, 0xd1, 0xa3, 0x7a, 0xa7, - 0x6d, 0x10, 0x13, 0xb3, 0x64, 0xa4, 0x6f, 0x39, 0x00, 0xb7, 0x91, 0xd9, 0xd8, 0x25, 0xa8, 0x5e, - 0xc5, 0x04, 0x95, 0x5a, 0xee, 0x21, 0x7c, 0x1b, 0xc4, 0xb0, 0xf7, 0x94, 0xe2, 0x32, 0xdc, 0xea, - 0xdc, 0xba, 0x90, 0x1d, 0x2f, 0x34, 0x3b, 0xf0, 0x57, 0x99, 0x37, 0xdc, 0x06, 0xb1, 0x47, 0x1e, - 0x5b, 0x2a, 0x9c, 0xe1, 0x56, 0xe3, 0xf2, 0xfb, 0x87, 0x7d, 0x31, 0xf4, 0x6b, 0x5f, 0xbc, 0xda, - 0x30, 0xc9, 0x6e, 0x67, 0x27, 0x5b, 0xc3, 0x16, 0xab, 0x8d, 0xfd, 0xb9, 0xe1, 0xd4, 0x3f, 0x5d, - 0x23, 0x07, 0x2d, 0xe4, 0x64, 0xf3, 0xa8, 0x76, 0xda, 0x17, 0x67, 0x0f, 0x0c, 0xab, 0xb9, 0x21, - 0x51, 0x16, 0x49, 0x65, 0x74, 0xd2, 0x36, 0x48, 0x6a, 0x68, 0x9f, 0x94, 0xdb, 0xb8, 0x85, 0x1d, - 0xa3, 0x09, 0x17, 0xc1, 0x14, 0x31, 0x49, 0x13, 0x79, 0xf9, 0xc5, 0x55, 0xfa, 0x02, 0x33, 0x20, - 0x51, 0x47, 0x4e, 0xad, 0x6d, 0xd2, 0xdc, 0xbd, 0x1c, 0xd4, 0xa0, 0x69, 0x63, 0xfe, 0xf5, 0x33, - 0x91, 0xfb, 0xe5, 0xfb, 0x1b, 0xd3, 0x9b, 0xd8, 0x26, 0xc8, 0x26, 0xd2, 0xcf, 0x1c, 0x98, 0xce, - 0xa3, 0x16, 0x76, 0x4c, 0x02, 0xdf, 0x01, 0x89, 0x16, 0x0b, 0xa0, 0x9b, 0x75, 0x8f, 0x3a, 0x2a, - 0x2f, 0x9d, 0xf6, 0x45, 0x48, 0x93, 0x0a, 0x1c, 0x4a, 0x2a, 0xf0, 0xdf, 0x0a, 0x75, 0x78, 0x05, - 0xc4, 0xeb, 0x94, 0x03, 0xb7, 0x59, 0xd4, 0x81, 0x01, 0xd6, 0x40, 0xcc, 0xb0, 0x70, 0xc7, 0x26, - 0xa9, 0x48, 0x26, 0xb2, 0x9a, 0x58, 0x5f, 0xf1, 0xc5, 0x74, 0x3b, 0xe4, 0x4c, 0xcd, 0x4d, 0x6c, - 0xda, 0xf2, 0x4d, 0x57, 0xaf, 0xef, 0x5e, 0x8a, 0xab, 0x6f, 0xa0, 0x97, 0x0b, 0x70, 0x54, 0x46, - 0xbd, 0x31, 0xf3, 0xf8, 0x99, 0x18, 0x7a, 0xfd, 0x4c, 0x0c, 0x49, 0x7f, 0xc6, 0xc0, 0xcc, 0x99, - 0x4e, 0x6f, 0x9d, 0x57, 0xd2, 0xc2, 0x49, 0x5f, 0x0c, 0x9b, 0xf5, 0xd3, 0xbe, 0x18, 0xa7, 0x85, - 0x8d, 0xd6, 0x73, 0x1b, 0x4c, 0xd7, 0xa8, 0x3e, 0x5e, 0x35, 0x89, 0xf5, 0xc5, 0x2c, 0xed, 0xa3, - 0xac, 0xdf, 0x47, 0xd9, 0x9c, 0x7d, 0x20, 0x27, 0x7e, 0x1c, 0x08, 0xa9, 0xfa, 0x08, 0x58, 0x05, - 0x31, 0x87, 0x18, 0xa4, 0xe3, 0xa4, 0x22, 0x5e, 0xef, 0x48, 0xe7, 0xf5, 0x8e, 0x9f, 0x60, 0xc5, - 0xf3, 0x94, 0xd3, 0xa7, 0x7d, 0x71, 0x69, 0x44, 0x64, 0x4a, 0x22, 0xa9, 0x8c, 0x0d, 0xb6, 0x00, - 0x7c, 0x68, 0xda, 0x46, 0x53, 0x27, 0x46, 0xb3, 0x79, 0xa0, 0xb7, 0x91, 0xd3, 0x69, 0x92, 0x54, - 0xd4, 0xcb, 0x4f, 0x3c, 0x2f, 0x86, 0xe6, 0xfa, 0xa9, 0x9e, 0x9b, 0xfc, 0x1f, 0x57, 0xd8, 0xd3, - 0xbe, 0xb8, 0x42, 0x83, 0x8c, 0x13, 0x49, 0x2a, 0xef, 0x19, 0x03, 0x20, 0xf8, 0x31, 0x48, 0x38, - 0x9d, 0x1d, 0xcb, 0x24, 0xba, 0x3b, 0x71, 0xa9, 0x29, 0x2f, 0x54, 0x7a, 0x4c, 0x0a, 0xcd, 0x1f, - 0x47, 0x59, 0x60, 0x51, 0x58, 0xbf, 0x04, 0xc0, 0xd2, 0x93, 0x97, 0x22, 0xa7, 0x02, 0x6a, 0x71, - 0x01, 0xd0, 0x04, 0x3c, 0x6b, 0x11, 0x1d, 0xd9, 0x75, 0x1a, 0x21, 0x76, 0x61, 0x84, 0xff, 0xb2, - 0x08, 0xcb, 0x34, 0xc2, 0x28, 0x03, 0x0d, 0x33, 0xc7, 0xcc, 0x8a, 0x5d, 0xf7, 0x42, 0x3d, 0xe6, - 0xc0, 0x2c, 0xc1, 0xc4, 0x68, 0xea, 0xec, 0x20, 0x35, 0x7d, 0x51, 0x23, 0xde, 0x61, 0x71, 0x16, - 0x69, 0x9c, 0x21, 0xb4, 0x34, 0x51, 0x83, 0x26, 0x3d, 0xac, 0x3f, 0x62, 0x4d, 0x70, 0x69, 0x0f, - 0x13, 0xd3, 0x6e, 0xb8, 0x3f, 0x6f, 0x9b, 0x09, 0x3b, 0x73, 0x61, 0xd9, 0xff, 0x63, 0xe9, 0xa4, - 0x68, 0x3a, 0x63, 0x14, 0xb4, 0xee, 0x79, 0x6a, 0xaf, 0xb8, 0x66, 0xaf, 0xf0, 0x87, 0x80, 0x99, - 0x06, 0x12, 0xc7, 0x2f, 0x8c, 0x25, 0xb1, 0x58, 0x4b, 0x43, 0xb1, 0x86, 0x15, 0x9e, 0xa5, 0x56, - 0x26, 0xf0, 0x46, 0xd4, 0xdd, 0x2a, 0xd2, 0x61, 0x18, 0x24, 0x82, 0xed, 0xf3, 0x01, 0x88, 0x1c, - 0x20, 0x87, 0x6e, 0x28, 0x39, 0x3b, 0xc1, 0x26, 0x2c, 0xd8, 0x44, 0x75, 0xa1, 0xf0, 0x0e, 0x98, - 0x36, 0x76, 0x1c, 0x62, 0x98, 0x6c, 0x97, 0x4d, 0xcc, 0xe2, 0xc3, 0xe1, 0x7b, 0x20, 0x6c, 0x63, - 0x6f, 0x20, 0x27, 0x27, 0x09, 0xdb, 0x18, 0x36, 0x40, 0xd2, 0xc6, 0xfa, 0x23, 0x93, 0xec, 0xea, - 0x7b, 0x88, 0x60, 0x6f, 0xec, 0xe2, 0xb2, 0x32, 0x19, 0xd3, 0x69, 0x5f, 0x5c, 0xa0, 0xa2, 0x06, - 0xb9, 0x24, 0x15, 0xd8, 0x78, 0xdb, 0x24, 0xbb, 0x55, 0x44, 0x30, 0x93, 0xf2, 0x98, 0x03, 0x51, - 0xf7, 0x7a, 0xf9, 0xe7, 0x2b, 0x79, 0x11, 0x4c, 0xed, 0x61, 0x82, 0xfc, 0x75, 0x4c, 0x5f, 0xe0, - 0xc6, 0xd9, 0xbd, 0x16, 0x79, 0x93, 0x7b, 0x4d, 0x0e, 0xa7, 0xb8, 0xb3, 0xbb, 0x6d, 0x0b, 0x4c, - 0xd3, 0x27, 0x27, 0x15, 0xf5, 0xc6, 0xe7, 0xea, 0x79, 0xe0, 0xf1, 0xcb, 0x54, 0x8e, 0xba, 0x2a, - 0xa9, 0x3e, 0x78, 0x63, 0xe6, 0xa9, 0xbf, 0xa9, 0x7f, 0x08, 0x83, 0x59, 0x36, 0x18, 0x65, 0xa3, - 0x6d, 0x58, 0x0e, 0xfc, 0x9a, 0x03, 0x09, 0xcb, 0xb4, 0xcf, 0xe6, 0x94, 0xbb, 0x68, 0x4e, 0x75, - 0x97, 0xfb, 0xa4, 0x2f, 0x5e, 0x0e, 0xa0, 0xae, 0x63, 0xcb, 0x24, 0xc8, 0x6a, 0x91, 0x83, 0x81, - 0x4e, 0x81, 0xe3, 0xc9, 0xc6, 0x17, 0x58, 0xa6, 0xed, 0x0f, 0xef, 0x57, 0x1c, 0x80, 0x96, 0xb1, - 0xef, 0x13, 0xe9, 0x2d, 0xd4, 0x36, 0x71, 0x9d, 0x5d, 0x11, 0x2b, 0x63, 0x23, 0x95, 0x67, 0x9f, - 0x1a, 0xb4, 0x4d, 0x4e, 0xfa, 0xe2, 0x95, 0x71, 0xf0, 0x50, 0xae, 0x6c, 0x39, 0x8f, 0x7b, 0x49, - 0x4f, 0xdd, 0xa1, 0xe3, 0x2d, 0x63, 0xdf, 0x97, 0x8b, 0x9a, 0xbf, 0xe4, 0x40, 0xb2, 0xea, 0x4d, - 0x22, 0xd3, 0xef, 0x73, 0xc0, 0x26, 0xd3, 0xcf, 0x8d, 0xbb, 0x28, 0xb7, 0xdb, 0x2c, 0xb7, 0xe5, - 0x21, 0xdc, 0x50, 0x5a, 0x8b, 0x43, 0x8b, 0x20, 0x98, 0x51, 0x92, 0xda, 0x58, 0x36, 0xbf, 0xf9, - 0xf3, 0xcf, 0x92, 0x79, 0x00, 0x62, 0x9f, 0x75, 0x70, 0xbb, 0x63, 0x79, 0x59, 0x24, 0x65, 0x79, - 0xb2, 0x8f, 0xa1, 0x93, 0xbe, 0xc8, 0x53, 0xfc, 0x20, 0x1b, 0x95, 0x31, 0xc2, 0x1a, 0x88, 0x93, - 0xdd, 0x36, 0x72, 0x76, 0x71, 0x93, 0xfe, 0x00, 0xc9, 0x89, 0x86, 0x91, 0xd2, 0x2f, 0x9c, 0x51, - 0x04, 0x22, 0x0c, 0x78, 0x61, 0x97, 0x03, 0x73, 0xee, 0x84, 0xea, 0x83, 0x50, 0x11, 0x2f, 0x54, - 0x6d, 0xe2, 0x50, 0xa9, 0x61, 0x9e, 0x21, 0x7d, 0x2f, 0x33, 0x7d, 0x87, 0x3c, 0x24, 0x75, 0xd6, - 0x35, 0x68, 0xfe, 0xfb, 0xb5, 0x3f, 0x38, 0x00, 0x02, 0x5f, 0xa8, 0xd7, 0xc1, 0x72, 0xb5, 0xa4, - 0x29, 0x7a, 0xa9, 0xac, 0x15, 0x4a, 0x45, 0xfd, 0x5e, 0xb1, 0x52, 0x56, 0x36, 0x0b, 0x5b, 0x05, - 0x25, 0xcf, 0x87, 0xd2, 0xf3, 0xdd, 0x5e, 0x26, 0x41, 0x1d, 0x15, 0x37, 0x08, 0x94, 0xc0, 0x7c, - 0xd0, 0xfb, 0xbe, 0x52, 0xe1, 0xb9, 0xf4, 0x6c, 0xb7, 0x97, 0x89, 0x53, 0xaf, 0xfb, 0xc8, 0x81, - 0xd7, 0xc0, 0x42, 0xd0, 0x27, 0x27, 0x57, 0xb4, 0x5c, 0xa1, 0xc8, 0x87, 0xd3, 0x97, 0xba, 0xbd, - 0xcc, 0x2c, 0xf5, 0xcb, 0xb1, 0x75, 0x9a, 0x01, 0x73, 0x41, 0xdf, 0x62, 0x89, 0x8f, 0xa4, 0x93, - 0xdd, 0x5e, 0x66, 0x86, 0xba, 0x15, 0x31, 0x5c, 0x07, 0xa9, 0x61, 0x0f, 0x7d, 0xbb, 0xa0, 0xdd, - 0xd1, 0xab, 0x8a, 0x56, 0xe2, 0xa3, 0xe9, 0xc5, 0x6e, 0x2f, 0xc3, 0xfb, 0xbe, 0xfe, 0xee, 0x4b, - 0x47, 0x1f, 0x7f, 0x23, 0x84, 0xae, 0xfd, 0x14, 0x06, 0x73, 0xc3, 0x9f, 0x47, 0x30, 0x0b, 0xfe, - 0x55, 0x56, 0x4b, 0xe5, 0x52, 0x25, 0x77, 0x57, 0xaf, 0x68, 0x39, 0xed, 0x5e, 0x65, 0xa4, 0x60, - 0xaf, 0x14, 0xea, 0x5c, 0x34, 0x9b, 0xf0, 0x36, 0x10, 0x46, 0xfd, 0xf3, 0x4a, 0xb9, 0x54, 0x29, - 0x68, 0x7a, 0x59, 0x51, 0x0b, 0xa5, 0x3c, 0xcf, 0xa5, 0x97, 0xbb, 0xbd, 0xcc, 0x02, 0x85, 0x0c, - 0x0d, 0x15, 0x7c, 0x17, 0xfc, 0x7b, 0x14, 0x5c, 0x2d, 0x69, 0x85, 0xe2, 0x87, 0x3e, 0x36, 0x9c, - 0x5e, 0xea, 0xf6, 0x32, 0x90, 0x62, 0xab, 0x81, 0x09, 0x80, 0xd7, 0xc1, 0xd2, 0x28, 0xb4, 0x9c, - 0xab, 0x54, 0x94, 0x3c, 0x1f, 0x49, 0xf3, 0xdd, 0x5e, 0x26, 0x49, 0x31, 0x65, 0xc3, 0x71, 0x50, - 0x1d, 0xde, 0x04, 0xa9, 0x51, 0x6f, 0x55, 0xf9, 0x48, 0xd9, 0xd4, 0x94, 0x3c, 0x1f, 0x4d, 0xc3, - 0x6e, 0x2f, 0x33, 0x47, 0xfd, 0x55, 0xf4, 0x09, 0xaa, 0x11, 0x74, 0x2e, 0xff, 0x56, 0xae, 0x70, - 0x57, 0xc9, 0xf3, 0x53, 0x41, 0xfe, 0x2d, 0xc3, 0x6c, 0xa2, 0x3a, 0x95, 0x53, 0x2e, 0x1e, 0xbe, - 0x12, 0x42, 0x2f, 0x5e, 0x09, 0xa1, 0x2f, 0x8e, 0x84, 0xd0, 0xe1, 0x91, 0xc0, 0x3d, 0x3f, 0x12, - 0xb8, 0xdf, 0x8f, 0x04, 0xee, 0xc9, 0xb1, 0x10, 0x7a, 0x7e, 0x2c, 0x84, 0x5e, 0x1c, 0x0b, 0xa1, - 0x07, 0x7f, 0xbf, 0x10, 0xf7, 0xbd, 0x7f, 0xff, 0xbc, 0x7e, 0xde, 0x89, 0x79, 0x3b, 0xe4, 0xff, - 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x14, 0xb4, 0xf2, 0xfe, 0x19, 0x0e, 0x00, 0x00, + // 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, } func (this *TextProposal) Equal(that interface{}) bool { @@ -1124,6 +1170,20 @@ func (m *VotingParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ProposalVotingPeriods) > 0 { + for iNdEx := len(m.ProposalVotingPeriods) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ProposalVotingPeriods[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGov(dAtA, i, uint64(size)) + } + i-- + 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 @@ -1188,6 +1248,44 @@ func (m *TallyParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ProposalVotingPeriod) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ProposalVotingPeriod) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProposalVotingPeriod) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = 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 + } + i -= n9 + i = encodeVarintGov(dAtA, i, uint64(n9)) + i-- + dAtA[i] = 0x12 + if len(m.ProposalType) > 0 { + i -= len(m.ProposalType) + copy(dAtA[i:], m.ProposalType) + i = encodeVarintGov(dAtA, i, uint64(len(m.ProposalType))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintGov(dAtA []byte, offset int, v uint64) int { offset -= sovGov(v) base := offset @@ -1354,6 +1452,12 @@ func (m *VotingParams) Size() (n int) { _ = l l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod) n += 1 + l + sovGov(uint64(l)) + if len(m.ProposalVotingPeriods) > 0 { + for _, e := range m.ProposalVotingPeriods { + l = e.Size() + n += 1 + l + sovGov(uint64(l)) + } + } return n } @@ -1372,6 +1476,21 @@ func (m *TallyParams) Size() (n int) { return n } +func (m *ProposalVotingPeriod) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ProposalType) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod) + n += 1 + l + sovGov(uint64(l)) + return n +} + func sovGov(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2572,6 +2691,40 @@ func (m *VotingParams) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalVotingPeriods", 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 + } + m.ProposalVotingPeriods = append(m.ProposalVotingPeriods, ProposalVotingPeriod{}) + if err := m.ProposalVotingPeriods[len(m.ProposalVotingPeriods)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGov(dAtA[iNdEx:]) @@ -2742,6 +2895,121 @@ func (m *TallyParams) Unmarshal(dAtA []byte) error { } return nil } +func (m *ProposalVotingPeriod) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ProposalVotingPeriod: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProposalVotingPeriod: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProposalType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VotingPeriod", 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.VotingPeriod, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipGov(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/gov/types/params.go b/x/gov/types/params.go index 95621e100f8e..b0b66075feae 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -1,7 +1,10 @@ package types import ( + "errors" "fmt" + "sort" + "strings" "time" yaml "gopkg.in/yaml.v2" @@ -136,20 +139,22 @@ func validateTallyParams(i interface{}) error { } // NewVotingParams creates a new VotingParams object -func NewVotingParams(votingPeriod time.Duration) VotingParams { +func NewVotingParams(votingPeriod time.Duration, pvps []ProposalVotingPeriod) VotingParams { return VotingParams{ - VotingPeriod: votingPeriod, + VotingPeriod: votingPeriod, + ProposalVotingPeriods: pvps, } } // DefaultVotingParams default parameters for voting func DefaultVotingParams() VotingParams { - return NewVotingParams(DefaultPeriod) + return NewVotingParams(DefaultPeriod, []ProposalVotingPeriod{}) } // Equal checks equality of TallyParams func (vp VotingParams) Equal(other VotingParams) bool { - return vp.VotingPeriod == other.VotingPeriod + return vp.VotingPeriod == other.VotingPeriod && + ProposalVotingPeriods(vp.ProposalVotingPeriods).Equal(ProposalVotingPeriods(other.ProposalVotingPeriods)) } // String implements stringer interface @@ -168,6 +173,15 @@ func validateVotingParams(i interface{}) error { return fmt.Errorf("voting period must be positive: %s", v.VotingPeriod) } + for _, pvp := range v.ProposalVotingPeriods { + if pvp.ProposalType == "" { + return errors.New("empty proposal type for proposal voting period") + } + if pvp.VotingPeriod <= 0 { + return fmt.Errorf("voting period must be positive for proposal voting period: %s", pvp.VotingPeriod) + } + } + return nil } @@ -196,3 +210,37 @@ func NewParams(vp VotingParams, tp TallyParams, dp DepositParams) Params { func DefaultParams() Params { return NewParams(DefaultVotingParams(), DefaultTallyParams(), DefaultDepositParams()) } + +func (pvp ProposalVotingPeriod) String() string { + out, _ := yaml.Marshal(pvp) + return string(out) +} + +// ProposalVotingPeriods defines a type alias for a slice of ProposalVotingPeriod +// objects. +type ProposalVotingPeriods []ProposalVotingPeriod + +func (pvps ProposalVotingPeriods) Equal(other ProposalVotingPeriods) bool { + sort.Slice(pvps, func(i, j int) bool { + return strings.Compare(pvps[i].ProposalType, pvps[j].ProposalType) < 0 + }) + + sort.Slice(other, func(i, j int) bool { + return strings.Compare(other[i].ProposalType, other[j].ProposalType) < 0 + }) + + if len(pvps) != len(other) { + return false + } + + for i := 0; i < len(pvps); i++ { + a := pvps[i] + b := other[i] + + if strings.Compare(a.ProposalType, b.ProposalType) != 0 || a.VotingPeriod != b.VotingPeriod { + return false + } + } + + return true +} From 08a6bbc6a19a9ee6a61dad49aabe4a9eec1ce51d Mon Sep 17 00:00:00 2001 From: John Letey Date: Sat, 18 Jun 2022 17:14:49 +0200 Subject: [PATCH 2/6] feat: expedited proposals (#2) * feat: expedited proposals h/t osmosis-labs/cosmos-sdk#240 * fix: correctly generate random threshold params * fix: update randomised genesis state tests --- docs/core/proto-docs.md | 4 + proto/cosmos/gov/v1beta1/gov.proto | 17 + proto/cosmos/gov/v1beta1/tx.proto | 3 +- x/distribution/client/cli/tx.go | 12 +- x/distribution/client/rest/rest.go | 2 +- x/distribution/client/rest/utils.go | 1 + x/gov/abci.go | 41 ++- x/gov/abci_test.go | 439 ++++++++++++++++++----- x/gov/client/cli/tx.go | 12 +- x/gov/client/rest/rest.go | 1 + x/gov/client/rest/tx.go | 2 +- x/gov/client/testutil/cli_test.go | 2 +- x/gov/client/testutil/suite.go | 8 +- x/gov/genesis_test.go | 8 +- x/gov/keeper/deposit_test.go | 2 +- x/gov/keeper/grpc_query_test.go | 33 +- x/gov/keeper/hooks_test.go | 4 +- x/gov/keeper/keeper_test.go | 14 +- x/gov/keeper/msg_server.go | 2 +- x/gov/keeper/proposal.go | 8 +- x/gov/keeper/proposal_test.go | 105 ++++-- x/gov/keeper/querier_test.go | 6 +- x/gov/keeper/tally.go | 6 +- x/gov/keeper/tally_test.go | 30 +- x/gov/keeper/vote_test.go | 2 +- x/gov/legacy/v040/migrate_test.go | 7 + x/gov/legacy/v043/json_test.go | 2 + x/gov/simulation/decoder_test.go | 4 +- x/gov/simulation/genesis.go | 52 ++- x/gov/simulation/genesis_test.go | 13 +- x/gov/simulation/operations.go | 2 +- x/gov/simulation/operations_test.go | 7 +- x/gov/simulation/params.go | 19 +- x/gov/simulation/params_test.go | 9 +- x/gov/spec/01_concepts.md | 6 + x/gov/types/events.go | 21 +- x/gov/types/genesis.go | 12 + x/gov/types/gov.pb.go | 346 ++++++++++++------ x/gov/types/keys.go | 2 +- x/gov/types/msgs.go | 3 +- x/gov/types/msgs_test.go | 20 +- x/gov/types/params.go | 67 +++- x/gov/types/proposal.go | 3 +- x/gov/types/tx.pb.go | 121 ++++--- x/params/client/cli/tx.go | 19 +- x/params/client/rest/rest.go | 4 +- x/params/client/utils/utils.go | 2 + x/params/proposal_handler_test.go | 2 +- x/params/simulation/operations.go | 2 + x/params/types/proposal/proposal.go | 2 +- x/params/types/proposal/proposal_test.go | 8 +- x/upgrade/client/cli/tx.go | 16 +- x/upgrade/client/rest/tx.go | 6 +- 53 files changed, 1129 insertions(+), 412 deletions(-) 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 } From 3abc1c5f77691cf5620ca25143738308f39f452b Mon Sep 17 00:00:00 2001 From: John Letey Date: Mon, 20 Jun 2022 17:25:57 +0200 Subject: [PATCH 3/6] feat: allow protocol stakers and delegators to vote (#3) --- simapp/app.go | 2 +- x/gov/keeper/keeper.go | 6 +++++- x/gov/keeper/tally.go | 24 ++++++++++++++++++++++-- x/gov/types/expected_keepers.go | 6 ++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/simapp/app.go b/simapp/app.go index 783774aa04c5..1fbb3496becf 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -278,7 +278,7 @@ func NewSimApp( AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) govKeeper := govkeeper.NewKeeper( appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, govRouter, + &stakingKeeper, nil, govRouter, ) app.GovKeeper = *govKeeper.SetHooks( diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index 9e639fe5d0fc..491dc17c5179 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -23,6 +23,9 @@ type Keeper struct { // The reference to the DelegationSet and ValidatorSet to get information about validators and delegators sk types.StakingKeeper + // The reference to the ProtocolDelegationSet and ProtocolValidatorSet to get information about protocol validators and delegators + rk types.RegistryKeeper + // GovHooks hooks types.GovHooks @@ -45,7 +48,7 @@ type Keeper struct { // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace types.ParamSubspace, - authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, rtr types.Router, + authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, rk types.RegistryKeeper, rtr types.Router, ) Keeper { // ensure governance module account is set @@ -64,6 +67,7 @@ func NewKeeper( authKeeper: authKeeper, bankKeeper: bankKeeper, sk: sk, + rk: rk, cdc: cdc, router: rtr, } diff --git a/x/gov/keeper/tally.go b/x/gov/keeper/tally.go index 9522d2d43bf2..a160dfa1663d 100644 --- a/x/gov/keeper/tally.go +++ b/x/gov/keeper/tally.go @@ -66,6 +66,20 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo return false }) + // + if keeper.rk != nil { + keeper.rk.IterateProtocolBonding(ctx, voter, func(poolId uint64, amount sdk.Int) (stop bool) { + for _, option := range vote.Options { + subPower := amount.ToDec().Mul(option.Weight) + results[option.Option] = results[option.Option].Add(subPower) + } + + totalVotingPower = totalVotingPower.Add(amount.ToDec()) + + return false + }) + } + keeper.deleteVote(ctx, vote.ProposalId, voter) return false }) @@ -89,14 +103,20 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo tallyParams := keeper.GetTallyParams(ctx) tallyResults = types.NewTallyResultFromMap(results) + totalProtocolBonded := sdk.ZeroInt() + if keeper.rk != nil { + totalProtocolBonded = keeper.rk.TotalProtocolBonding(ctx) + } + totalBonded := keeper.sk.TotalBondedTokens(ctx).Add(totalProtocolBonded) + // TODO: Upgrade the spec to cover all of these cases & remove pseudocode. // If there is no staked coins, the proposal fails - if keeper.sk.TotalBondedTokens(ctx).IsZero() { + if totalBonded.IsZero() { return false, false, tallyResults } // If there is not enough quorum of votes, the proposal fails - percentVoting := totalVotingPower.Quo(keeper.sk.TotalBondedTokens(ctx).ToDec()) + percentVoting := totalVotingPower.Quo(totalBonded.ToDec()) if percentVoting.LT(tallyParams.Quorum) { return false, true, tallyResults } diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index a6e521647f31..acc21dcdf0ca 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -26,6 +26,12 @@ type StakingKeeper interface { ) } +// RegistryKeeper expected registry keeper (Protocol Validator and Delegator sets) (noalias) +type RegistryKeeper interface { + IterateProtocolBonding(ctx sdk.Context, address sdk.AccAddress, fn func(poolId uint64, amount sdk.Int) (stop bool)) + TotalProtocolBonding(ctx sdk.Context) sdk.Int +} + // AccountKeeper defines the expected account keeper (noalias) type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI From 8e803c7d7ccaf41d0053ccc1403ede7165bc629d Mon Sep 17 00:00:00 2001 From: John Letey Date: Tue, 21 Jun 2022 15:44:13 +0200 Subject: [PATCH 4/6] feat: expedited deposits (#4) h/t osmosis-labs/cosmos-sdk#254 --- docs/core/proto-docs.md | 1 + proto/cosmos/gov/v1beta1/gov.proto | 9 +- x/gov/abci.go | 3 +- x/gov/abci_test.go | 34 +++- x/gov/client/testutil/cli_test.go | 2 +- x/gov/client/testutil/suite.go | 7 +- x/gov/keeper/deposit.go | 3 +- x/gov/keeper/deposit_test.go | 212 ++++++++++++----------- x/gov/legacy/v040/migrate_test.go | 3 +- x/gov/legacy/v043/json_test.go | 3 +- x/gov/simulation/genesis.go | 16 +- x/gov/simulation/genesis_test.go | 17 +- x/gov/types/genesis.go | 17 +- x/gov/types/gov.pb.go | 261 ++++++++++++++++++----------- x/gov/types/params.go | 31 ++-- x/gov/types/proposal.go | 10 ++ x/gov/types/proposals_test.go | 31 ++++ x/params/proposal_handler_test.go | 18 +- 18 files changed, 440 insertions(+), 238 deletions(-) diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 2a3157bcfa49..4aa6a09efe4a 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -5087,6 +5087,7 @@ DepositParams defines the params for deposits on governance proposals. | ----- | ---- | ----- | ----------- | | `min_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Minimum deposit for a proposal to enter voting period. | | `max_deposit_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months. | +| `min_expedited_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Minimum expedited deposit for a proposal to enter voting period. | diff --git a/proto/cosmos/gov/v1beta1/gov.proto b/proto/cosmos/gov/v1beta1/gov.proto index 4935d1721b08..7171dee98459 100644 --- a/proto/cosmos/gov/v1beta1/gov.proto +++ b/proto/cosmos/gov/v1beta1/gov.proto @@ -160,6 +160,14 @@ message DepositParams { (gogoproto.jsontag) = "max_deposit_period,omitempty", (gogoproto.moretags) = "yaml:\"max_deposit_period\"" ]; + + // Minimum expedited deposit for a proposal to enter voting period. + repeated cosmos.base.v1beta1.Coin min_expedited_deposit = 3 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"min_expedited_deposit\"", + (gogoproto.jsontag) = "min_expedited_deposit,omitempty" + ]; } // VotingParams defines the params for voting on governance proposals. @@ -210,7 +218,6 @@ message TallyParams { (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", diff --git a/x/gov/abci.go b/x/gov/abci.go index 4883b25cae72..8749fc7f685e 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -35,8 +35,9 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { logger.Info( "proposal did not meet minimum deposit; deleted", "proposal", proposal.ProposalId, + "is_expedited", proposal.IsExpedited, "title", proposal.GetTitle(), - "min_deposit", keeper.GetDepositParams(ctx).MinDeposit.String(), + "min_deposit", proposal.GetMinDepositFromParams(keeper.GetDepositParams(ctx)).String(), "total_deposit", proposal.TotalDeposit.String(), ) diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 2d2086e815d4..c78759a5a595 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -224,6 +224,8 @@ func TestTickPassedVotingPeriod(t *testing.T) { t.Run(tc.name, func(t *testing.T) { testProposal := TestProposal + depositMultiplier := getDepositMultiplier(tc.isExpedited) + app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) @@ -242,7 +244,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { require.False(t, activeQueue.Valid()) activeQueue.Close() - proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))} + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5*depositMultiplier))} newProposalMsg, err := types.NewMsgSubmitProposal(testProposal, proposalCoins, addrs[0], tc.isExpedited) require.NoError(t, err) @@ -319,15 +321,15 @@ func TestTickPassedVotingPeriod(t *testing.T) { func TestProposalPassedEndblocker(t *testing.T) { testcases := []struct { name string - IsExpedited bool + isExpedited bool }{ { name: "regular text", - IsExpedited: false, + isExpedited: false, }, { name: "text expedited", - IsExpedited: true, + isExpedited: true, }, } @@ -335,9 +337,11 @@ func TestProposalPassedEndblocker(t *testing.T) { t.Run(tc.name, func(t *testing.T) { testProposal := TestProposal + depositMultiplier := getDepositMultiplier(tc.isExpedited) + app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens.Mul(sdk.NewInt(depositMultiplier))) SortAddresses(addrs) @@ -356,10 +360,10 @@ func TestProposalPassedEndblocker(t *testing.T) { require.NotNil(t, macc) initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) - proposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal, tc.IsExpedited) + proposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal, tc.isExpedited) require.NoError(t, err) - proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))} + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10*depositMultiplier))} newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) handleAndCheck(t, handler, ctx, newDepositMsg) @@ -415,9 +419,11 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { t.Run(tc.name, func(t *testing.T) { testProposal := TestProposal + depositMultiplier := getDepositMultiplier(true) + app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens) + addrs := simapp.AddTestAddrs(app, ctx, 10, valTokens.Mul(sdk.NewInt(depositMultiplier))) SortAddresses(addrs) @@ -447,7 +453,7 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { 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))} + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5*depositMultiplier))} newProposalMsg, err := types.NewMsgSubmitProposal(testProposal, proposalCoins, addrs[0], true) require.NoError(t, err) @@ -639,3 +645,13 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { // validate that the proposal fails/has been rejected gov.EndBlocker(ctx, app.GovKeeper) } + +// With expedited proposal's minimum deposit set higher than the default deposit, we must +// initialize and deposit an amount depositMultiplier times larger +// than the regular min deposit amount. +func getDepositMultiplier(isExpedited bool) int64 { + if !isExpedited { + return 1 + } + return types.DefaultMinExpeditedDepositTokens.Quo(types.DefaultMinDepositTokens).Int64() +} diff --git a/x/gov/client/testutil/cli_test.go b/x/gov/client/testutil/cli_test.go index 60e0b7ce8d61..46252a20dafb 100644 --- a/x/gov/client/testutil/cli_test.go +++ b/x/gov/client/testutil/cli_test.go @@ -21,7 +21,7 @@ func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, NewIntegrationTestSuite(cfg)) genesisState := types.DefaultGenesisState() - genesisState.DepositParams = types.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinDepositTokens)), time.Duration(15)*time.Second) + genesisState.DepositParams = types.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinDepositTokens)), time.Duration(15)*time.Second, sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinExpeditedDepositTokens))) 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) diff --git a/x/gov/client/testutil/suite.go b/x/gov/client/testutil/suite.go index ef3e4b38912e..2b7fe39f95d7 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,"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"}}`, + `{"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","min_expedited_deposit":[{"denom":"stake","amount":"50000000"}]}}`, }, { "text output", @@ -99,6 +99,9 @@ deposit_params: min_deposit: - amount: "10000000" denom: stake + min_expedited_deposit: + - amount: "50000000" + denom: stake tally_params: expedited_threshold: "0.667000000000000000" quorum: "0.334000000000000000" @@ -156,7 +159,7 @@ func (s *IntegrationTestSuite) TestCmdParam() { "deposit", fmt.Sprintf("--%s=json", tmcli.OutputFlag), }, - `{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}`, + `{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000","min_expedited_deposit":[{"denom":"stake","amount":"50000000"}]}`, }, } diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index dcd47fe3096d..027416015ada 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -130,7 +130,8 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd // Check if deposit has provided sufficient total funds to transition the proposal into the voting period activatedVotingPeriod := false - if proposal.Status == types.StatusDepositPeriod && proposal.TotalDeposit.IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) { + minDepositAmount := proposal.GetMinDepositFromParams(keeper.GetDepositParams(ctx)) + if proposal.Status == types.StatusDepositPeriod && proposal.TotalDeposit.IsAllGTE(minDepositAmount) { keeper.ActivateVotingPeriod(ctx, proposal) activatedVotingPeriod = true diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index 9f2e5b92407e..7014a3411929 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -9,102 +9,124 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" ) func TestDeposits(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - - TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000000)) - - tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, false) - require.NoError(t, err) - proposalID := proposal.ProposalId - - fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 4))) - fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))) - - addr0Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]) - addr1Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[1]) - - require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins())) - - // Check no deposits at beginning - deposit, found := app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) - require.False(t, found) - proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) - require.True(t, ok) - require.True(t, proposal.VotingStartTime.Equal(time.Time{})) - - // Check first deposit - votingStarted, err := app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) - require.NoError(t, err) - require.False(t, votingStarted) - deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0]) - require.True(t, found) - require.Equal(t, fourStake, deposit.Amount) - require.Equal(t, TestAddrs[0].String(), deposit.Depositor) - proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) - require.True(t, ok) - require.Equal(t, fourStake, proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) - - // Check a second deposit from same address - votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) - require.NoError(t, err) - require.False(t, votingStarted) - deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0]) - require.True(t, found) - require.Equal(t, fourStake.Add(fiveStake...), deposit.Amount) - require.Equal(t, TestAddrs[0].String(), deposit.Depositor) - proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) - require.True(t, ok) - require.Equal(t, fourStake.Add(fiveStake...), proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) - - // Check third deposit from a new address - votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) - require.NoError(t, err) - require.True(t, votingStarted) - deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) - require.True(t, found) - require.Equal(t, TestAddrs[1].String(), deposit.Depositor) - require.Equal(t, fourStake, deposit.Amount) - proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) - require.True(t, ok) - require.Equal(t, fourStake.Add(fiveStake...).Add(fourStake...), proposal.TotalDeposit) - require.Equal(t, addr1Initial.Sub(fourStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) - - // Check that proposal moved to voting period - proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) - require.True(t, ok) - require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) - - // Test deposit iterator - // NOTE order of deposits is determined by the addresses - deposits := app.GovKeeper.GetAllDeposits(ctx) - require.Len(t, deposits, 2) - require.Equal(t, deposits, app.GovKeeper.GetDeposits(ctx, proposalID)) - require.Equal(t, TestAddrs[0].String(), deposits[0].Depositor) - require.Equal(t, fourStake.Add(fiveStake...), deposits[0].Amount) - require.Equal(t, TestAddrs[1].String(), deposits[1].Depositor) - require.Equal(t, fourStake, deposits[1].Amount) - - // Test Refund Deposits - deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) - require.True(t, found) - require.Equal(t, fourStake, deposit.Amount) - app.GovKeeper.RefundDeposits(ctx, proposalID) - deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) - require.False(t, found) - require.Equal(t, addr0Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) - require.Equal(t, addr1Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) - - // Test delete deposits - _, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) - require.NoError(t, err) - app.GovKeeper.DeleteDeposits(ctx, proposalID) - deposits = app.GovKeeper.GetDeposits(ctx, proposalID) - require.Len(t, deposits, 0) + testcases := map[string]struct { + isExpedited bool + }{ + "regular": { + isExpedited: false, + }, + "expedited": { + isExpedited: true, + }, + } + + for _, tc := range testcases { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + // With expedited proposals the minimum deposit is higher, so we must + // initialize and deposit an amount depositMultiplier times larger + // than the regular min deposit amount. + depositMultiplier := int64(1) + if tc.isExpedited { + depositMultiplier = types.DefaultMinExpeditedDepositTokens.Quo(types.DefaultMinDepositTokens).Int64() + } + + TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000000*depositMultiplier)) + + tp := TestProposal + proposal, err := app.GovKeeper.SubmitProposal(ctx, tp, tc.isExpedited) + require.NoError(t, err) + proposalID := proposal.ProposalId + + firstDepositValue := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 4*depositMultiplier))) + secondDepositValue := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5*depositMultiplier))) + + addr0Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]) + addr1Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[1]) + + require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins())) + + // Check no deposits at beginning + deposit, found := app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + require.False(t, found) + proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + require.True(t, proposal.VotingStartTime.Equal(time.Time{})) + + // Check first deposit + votingStarted, err := app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], firstDepositValue) + require.NoError(t, err) + require.False(t, votingStarted) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0]) + require.True(t, found) + require.Equal(t, firstDepositValue, deposit.Amount) + require.Equal(t, TestAddrs[0].String(), deposit.Depositor) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + require.Equal(t, firstDepositValue, proposal.TotalDeposit) + require.Equal(t, addr0Initial.Sub(firstDepositValue), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) + + // Check a second deposit from same address + votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], secondDepositValue) + require.NoError(t, err) + require.False(t, votingStarted) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0]) + require.True(t, found) + require.Equal(t, firstDepositValue.Add(secondDepositValue...), deposit.Amount) + require.Equal(t, TestAddrs[0].String(), deposit.Depositor) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + require.Equal(t, firstDepositValue.Add(secondDepositValue...), proposal.TotalDeposit) + require.Equal(t, addr0Initial.Sub(firstDepositValue).Sub(secondDepositValue), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) + + // Check third deposit from a new address + votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[1], firstDepositValue) + require.NoError(t, err) + require.True(t, votingStarted) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + require.True(t, found) + require.Equal(t, TestAddrs[1].String(), deposit.Depositor) + require.Equal(t, firstDepositValue, deposit.Amount) + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + require.Equal(t, firstDepositValue.Add(secondDepositValue...).Add(firstDepositValue...), proposal.TotalDeposit) + require.Equal(t, addr1Initial.Sub(firstDepositValue), app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) + + // Check that proposal moved to voting period + proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID) + require.True(t, ok) + require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) + + // Test deposit iterator + // NOTE order of deposits is determined by the addresses + deposits := app.GovKeeper.GetAllDeposits(ctx) + require.Len(t, deposits, 2) + require.Equal(t, deposits, app.GovKeeper.GetDeposits(ctx, proposalID)) + require.Equal(t, TestAddrs[0].String(), deposits[0].Depositor) + require.Equal(t, firstDepositValue.Add(secondDepositValue...), deposits[0].Amount) + require.Equal(t, TestAddrs[1].String(), deposits[1].Depositor) + require.Equal(t, firstDepositValue, deposits[1].Amount) + + // Test Refund Deposits + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + require.True(t, found) + require.Equal(t, firstDepositValue, deposit.Amount) + app.GovKeeper.RefundDeposits(ctx, proposalID) + deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1]) + require.False(t, found) + require.Equal(t, addr0Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) + require.Equal(t, addr1Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) + + // Test delete deposits + _, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], firstDepositValue) + require.NoError(t, err) + app.GovKeeper.DeleteDeposits(ctx, proposalID) + deposits = app.GovKeeper.GetDeposits(ctx, proposalID) + require.Len(t, deposits, 0) + } } diff --git a/x/gov/legacy/v040/migrate_test.go b/x/gov/legacy/v040/migrate_test.go index 1ac128b133e8..9d9fb3263399 100644 --- a/x/gov/legacy/v040/migrate_test.go +++ b/x/gov/legacy/v040/migrate_test.go @@ -97,7 +97,8 @@ func TestMigrate(t *testing.T) { expected := `{ "deposit_params": { "max_deposit_period": "0s", - "min_deposit": [] + "min_deposit": [], + "min_expedited_deposit": [] }, "deposits": [], "proposals": [ diff --git a/x/gov/legacy/v043/json_test.go b/x/gov/legacy/v043/json_test.go index 6cdcb5b0e602..3e24b31aa2c1 100644 --- a/x/gov/legacy/v043/json_test.go +++ b/x/gov/legacy/v043/json_test.go @@ -50,7 +50,8 @@ func TestMigrateJSON(t *testing.T) { expected := `{ "deposit_params": { "max_deposit_period": "0s", - "min_deposit": [] + "min_deposit": [], + "min_expedited_deposit": [] }, "deposits": [], "proposals": [], diff --git a/x/gov/simulation/genesis.go b/x/gov/simulation/genesis.go index d7ef7c2e5351..c25fa6080fb0 100644 --- a/x/gov/simulation/genesis.go +++ b/x/gov/simulation/genesis.go @@ -17,6 +17,7 @@ import ( // Simulation parameter constants const ( DepositParamsMinDeposit = "deposit_params_min_deposit" + DepositParamsMinExpeditedDeposit = "deposit_params_min_expedited_deposit" DepositParamsDepositPeriod = "deposit_params_deposit_period" VotingParamsVotingPeriod = "voting_params_voting_period" ExpeditedVotingParamsVotingPeriod = "expedited_voting_params_voting_period" @@ -41,7 +42,12 @@ func GenDepositParamsDepositPeriod(r *rand.Rand) time.Duration { // GenDepositParamsMinDeposit randomized DepositParamsMinDeposit func GenDepositParamsMinDeposit(r *rand.Rand) sdk.Coins { - return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 1, 1e3)))) + return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 1, 1e3/2)))) +} + +// GenDepositParamsMinExpeditedDeposit randomized DepositParamsMinExpeditedDeposit +func GenDepositParamsMinExpeditedDeposit(r *rand.Rand) sdk.Coins { + return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 1e3/2, 1e3)))) } // GenVotingParamsVotingPeriod randomized VotingParamsVotingPeriod @@ -84,6 +90,12 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { minDeposit = GenDepositParamsMinDeposit(r) }, ) + var minExpeditedDeposit sdk.Coins + simState.AppParams.GetOrGenerate( + simState.Cdc, DepositParamsMinExpeditedDeposit, &minExpeditedDeposit, simState.Rand, + func(r *rand.Rand) { minExpeditedDeposit = GenDepositParamsMinExpeditedDeposit(r) }, + ) + var depositPeriod time.Duration simState.AppParams.GetOrGenerate( simState.Cdc, DepositParamsDepositPeriod, &depositPeriod, simState.Rand, @@ -143,7 +155,7 @@ func RandomizedGenState(simState *module.SimulationState) { govGenesis := types.NewGenesisState( startingProposalID, - types.NewDepositParams(minDeposit, depositPeriod), + types.NewDepositParams(minDeposit, depositPeriod, minExpeditedDeposit), types.NewVotingParams(votingPeriod, expeditedVotingPeriod, proposalVotingPeriods), types.NewTallyParams(quorum, threshold, expeditedThreshold, veto), ) diff --git a/x/gov/simulation/genesis_test.go b/x/gov/simulation/genesis_test.go index e3bf9a8e0a2a..ce616a509095 100644 --- a/x/gov/simulation/genesis_test.go +++ b/x/gov/simulation/genesis_test.go @@ -40,15 +40,16 @@ func TestRandomizedGenState(t *testing.T) { var govGenesis types.GenesisState simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &govGenesis) - dec1, _ := sdk.NewDecFromStr("0.400000000000000000") - dec2, _ := sdk.NewDecFromStr("0.489000000000000000") - dec3, _ := sdk.NewDecFromStr("0.509000000000000000") - dec4, _ := sdk.NewDecFromStr("0.324000000000000000") + dec1, _ := sdk.NewDecFromStr("0.375000000000000000") + dec2, _ := sdk.NewDecFromStr("0.478000000000000000") + dec3, _ := sdk.NewDecFromStr("0.533000000000000000") + dec4, _ := sdk.NewDecFromStr("0.313000000000000000") - require.Equal(t, "905stake", govGenesis.DepositParams.MinDeposit.String()) - require.Equal(t, "77h26m10s", govGenesis.DepositParams.MaxDepositPeriod.String()) - require.Equal(t, float64(317894), govGenesis.VotingParams.VotingPeriod.Seconds()) - require.Equal(t, float64(107823), govGenesis.VotingParams.ExpeditedVotingPeriod.Seconds()) + require.Equal(t, "272stake", govGenesis.DepositParams.MinDeposit.String()) + require.Equal(t, "41h11m36s", govGenesis.DepositParams.MaxDepositPeriod.String()) + require.Equal(t, "800stake", govGenesis.DepositParams.MinExpeditedDeposit.String()) + require.Equal(t, float64(270511), govGenesis.VotingParams.VotingPeriod.Seconds()) + require.Equal(t, float64(137225), govGenesis.VotingParams.ExpeditedVotingPeriod.Seconds()) require.Equal(t, dec1, govGenesis.TallyParams.Quorum) require.Equal(t, dec2, govGenesis.TallyParams.Threshold) require.Equal(t, dec3, govGenesis.TallyParams.ExpeditedThreshold) diff --git a/x/gov/types/genesis.go b/x/gov/types/genesis.go index 84fed2e13f87..f703863736c8 100644 --- a/x/gov/types/genesis.go +++ b/x/gov/types/genesis.go @@ -68,9 +68,22 @@ func ValidateGenesis(data *GenesisState) error { veto.String()) } - if !data.DepositParams.MinDeposit.IsValid() { + minDeposit := data.DepositParams.MinDeposit + if !minDeposit.IsValid() { return fmt.Errorf("governance deposit amount must be a valid sdk.Coins amount, is %s", - data.DepositParams.MinDeposit.String()) + minDeposit.String()) + } + + minExpeditedDeposit := data.DepositParams.MinExpeditedDeposit + if !minExpeditedDeposit.IsValid() { + return fmt.Errorf("governance expedited deposit amount must be a valid sdk.Coins amount, is %s", + minExpeditedDeposit.String()) + } + + if minExpeditedDeposit.IsAllLTE(minDeposit) { + return fmt.Errorf("governance min expedited deposit amount %s must be greater than regular min deposit %s", + minExpeditedDeposit.String(), + minDeposit.String()) } return nil diff --git a/x/gov/types/gov.pb.go b/x/gov/types/gov.pb.go index b0ed836e3270..28ca20326ab4 100644 --- a/x/gov/types/gov.pb.go +++ b/x/gov/types/gov.pb.go @@ -378,6 +378,8 @@ type DepositParams struct { // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 // months. MaxDepositPeriod time.Duration `protobuf:"bytes,2,opt,name=max_deposit_period,json=maxDepositPeriod,proto3,stdduration" json:"max_deposit_period,omitempty" yaml:"max_deposit_period"` + // Minimum expedited deposit for a proposal to enter voting period. + MinExpeditedDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=min_expedited_deposit,json=minExpeditedDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"min_expedited_deposit,omitempty" yaml:"min_expedited_deposit"` } func (m *DepositParams) Reset() { *m = DepositParams{} } @@ -557,107 +559,110 @@ func init() { func init() { proto.RegisterFile("cosmos/gov/v1beta1/gov.proto", fileDescriptor_6e82113c1a9a4b7c) } var fileDescriptor_6e82113c1a9a4b7c = []byte{ - // 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, + // 1634 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcf, 0x6f, 0xe2, 0xda, + 0x15, 0xc6, 0x40, 0x7e, 0x70, 0x81, 0x84, 0x77, 0x43, 0x12, 0x42, 0xf3, 0x6c, 0xc6, 0xaf, 0x7a, + 0x8a, 0x46, 0xf3, 0xc8, 0x7b, 0x69, 0xd5, 0xaa, 0x19, 0xa9, 0x2d, 0x04, 0xa7, 0x43, 0xf5, 0x04, + 0xc8, 0xf0, 0x88, 0xde, 0xeb, 0xc2, 0x72, 0xe0, 0x86, 0xb8, 0xc5, 0xbe, 0x14, 0x5f, 0x32, 0x41, + 0xdd, 0x8c, 0xd4, 0xcd, 0x88, 0x45, 0x35, 0xcb, 0xa9, 0x2a, 0xa4, 0x51, 0xab, 0x6e, 0xba, 0xee, + 0xa2, 0xeb, 0xae, 0xa2, 0xaa, 0x52, 0x47, 0x5d, 0x8d, 0xba, 0x60, 0x3a, 0x89, 0x54, 0x8d, 0xb2, + 0xcc, 0x5f, 0x50, 0xd9, 0xf7, 0xda, 0xd8, 0xc0, 0x0c, 0x43, 0x17, 0x5d, 0xc5, 0x9c, 0x7b, 0xbe, + 0xef, 0x9c, 0xf3, 0x71, 0xce, 0xb9, 0x26, 0x60, 0xb7, 0x81, 0x4d, 0x1d, 0x9b, 0xfb, 0x2d, 0x7c, + 0xb1, 0x7f, 0xf1, 0xc5, 0x29, 0x22, 0xea, 0x17, 0xd6, 0x73, 0xb6, 0xd3, 0xc5, 0x04, 0x43, 0x48, + 0x4f, 0xb3, 0x96, 0x85, 0x9d, 0xa6, 0x79, 0x86, 0x38, 0x55, 0x4d, 0xe4, 0x42, 0x1a, 0x58, 0x33, + 0x28, 0x26, 0x9d, 0x6c, 0xe1, 0x16, 0xb6, 0x1f, 0xf7, 0xad, 0x27, 0x66, 0xdd, 0xa1, 0x28, 0x85, + 0x1e, 0x30, 0x5a, 0x7a, 0x24, 0xb4, 0x30, 0x6e, 0xb5, 0xd1, 0xbe, 0xfd, 0xe9, 0xb4, 0x77, 0xb6, + 0x4f, 0x34, 0x1d, 0x99, 0x44, 0xd5, 0x3b, 0x0e, 0x76, 0xd2, 0x41, 0x35, 0xfa, 0xec, 0x88, 0x9f, + 0x3c, 0x6a, 0xf6, 0xba, 0x2a, 0xd1, 0x30, 0x4b, 0x46, 0xfc, 0x23, 0x07, 0xe0, 0x09, 0xd2, 0x5a, + 0xe7, 0x04, 0x35, 0xeb, 0x98, 0xa0, 0x72, 0xc7, 0x3a, 0x84, 0xdf, 0x03, 0xcb, 0xd8, 0x7e, 0x4a, + 0x71, 0x19, 0x6e, 0x6f, 0xed, 0x80, 0xcf, 0x4e, 0x17, 0x9a, 0x1d, 0xfb, 0xcb, 0xcc, 0x1b, 0x9e, + 0x80, 0xe5, 0xc7, 0x36, 0x5b, 0x2a, 0x98, 0xe1, 0xf6, 0x22, 0xf9, 0x1f, 0x5d, 0x8d, 0x84, 0xc0, + 0xbf, 0x46, 0xc2, 0xa7, 0x2d, 0x8d, 0x9c, 0xf7, 0x4e, 0xb3, 0x0d, 0xac, 0xb3, 0xda, 0xd8, 0x9f, + 0xcf, 0xcc, 0xe6, 0x2f, 0xf6, 0x49, 0xbf, 0x83, 0xcc, 0x6c, 0x01, 0x35, 0xee, 0x46, 0x42, 0xbc, + 0xaf, 0xea, 0xed, 0x43, 0x91, 0xb2, 0x88, 0x32, 0xa3, 0x13, 0x4f, 0x40, 0xac, 0x86, 0x2e, 0x49, + 0xa5, 0x8b, 0x3b, 0xd8, 0x54, 0xdb, 0x30, 0x09, 0x96, 0x88, 0x46, 0xda, 0xc8, 0xce, 0x2f, 0x22, + 0xd3, 0x0f, 0x30, 0x03, 0xa2, 0x4d, 0x64, 0x36, 0xba, 0x1a, 0xcd, 0xdd, 0xce, 0x41, 0xf6, 0x9a, + 0x0e, 0xd7, 0xdf, 0xbe, 0x10, 0xb8, 0x7f, 0xfe, 0xf9, 0xb3, 0x95, 0x23, 0x6c, 0x10, 0x64, 0x10, + 0xf1, 0x1f, 0x1c, 0x58, 0x29, 0xa0, 0x0e, 0x36, 0x35, 0x02, 0xbf, 0x0f, 0xa2, 0x1d, 0x16, 0x40, + 0xd1, 0x9a, 0x36, 0x75, 0x38, 0xbf, 0x75, 0x37, 0x12, 0x20, 0x4d, 0xca, 0x73, 0x28, 0xca, 0xc0, + 0xf9, 0x54, 0x6c, 0xc2, 0x5d, 0x10, 0x69, 0x52, 0x0e, 0xdc, 0x65, 0x51, 0xc7, 0x06, 0xd8, 0x00, + 0xcb, 0xaa, 0x8e, 0x7b, 0x06, 0x49, 0x85, 0x32, 0xa1, 0xbd, 0xe8, 0xc1, 0x8e, 0x23, 0xa6, 0xd5, + 0x21, 0xae, 0x9a, 0x47, 0x58, 0x33, 0xf2, 0x9f, 0x5b, 0x7a, 0xfd, 0xe9, 0xb5, 0xb0, 0xf7, 0x01, + 0x7a, 0x59, 0x00, 0x53, 0x66, 0xd4, 0x87, 0xab, 0x4f, 0x5f, 0x08, 0x81, 0xb7, 0x2f, 0x84, 0x80, + 0xf8, 0xdb, 0x15, 0xb0, 0xea, 0xea, 0xf4, 0xdd, 0x59, 0x25, 0x6d, 0xdc, 0x8e, 0x84, 0xa0, 0xd6, + 0xbc, 0x1b, 0x09, 0x11, 0x5a, 0xd8, 0x64, 0x3d, 0x0f, 0xc1, 0x4a, 0x83, 0xea, 0x63, 0x57, 0x13, + 0x3d, 0x48, 0x66, 0x69, 0x1f, 0x65, 0x9d, 0x3e, 0xca, 0xe6, 0x8c, 0x7e, 0x3e, 0xfa, 0xb7, 0xb1, + 0x90, 0xb2, 0x83, 0x80, 0x75, 0xb0, 0x6c, 0x12, 0x95, 0xf4, 0xcc, 0x54, 0xc8, 0xee, 0x1d, 0x71, + 0x56, 0xef, 0x38, 0x09, 0x56, 0x6d, 0xcf, 0x7c, 0xfa, 0x6e, 0x24, 0x6c, 0x4d, 0x88, 0x4c, 0x49, + 0x44, 0x99, 0xb1, 0xc1, 0x0e, 0x80, 0x67, 0x9a, 0xa1, 0xb6, 0x15, 0xa2, 0xb6, 0xdb, 0x7d, 0xa5, + 0x8b, 0xcc, 0x5e, 0x9b, 0xa4, 0xc2, 0x76, 0x7e, 0xc2, 0xac, 0x18, 0x35, 0xcb, 0x4f, 0xb6, 0xdd, + 0xf2, 0xf7, 0x2c, 0x61, 0xef, 0x46, 0xc2, 0x0e, 0x0d, 0x32, 0x4d, 0x24, 0xca, 0x09, 0xdb, 0xe8, + 0x01, 0xc1, 0x9f, 0x81, 0xa8, 0xd9, 0x3b, 0xd5, 0x35, 0xa2, 0x58, 0x13, 0x97, 0x5a, 0xb2, 0x43, + 0xa5, 0xa7, 0xa4, 0xa8, 0x39, 0xe3, 0x98, 0xe7, 0x59, 0x14, 0xd6, 0x2f, 0x1e, 0xb0, 0xf8, 0xec, + 0xb5, 0xc0, 0xc9, 0x80, 0x5a, 0x2c, 0x00, 0xd4, 0x40, 0x82, 0xb5, 0x88, 0x82, 0x8c, 0x26, 0x8d, + 0xb0, 0x3c, 0x37, 0xc2, 0x27, 0x2c, 0xc2, 0x36, 0x8d, 0x30, 0xc9, 0x40, 0xc3, 0xac, 0x31, 0xb3, + 0x64, 0x34, 0xed, 0x50, 0x4f, 0x39, 0x10, 0x27, 0x98, 0xa8, 0x6d, 0x85, 0x1d, 0xa4, 0x56, 0xe6, + 0x35, 0xe2, 0x23, 0x16, 0x27, 0x49, 0xe3, 0xf8, 0xd0, 0xe2, 0x42, 0x0d, 0x1a, 0xb3, 0xb1, 0xce, + 0x88, 0xb5, 0xc1, 0x47, 0x17, 0x98, 0x68, 0x46, 0xcb, 0xfa, 0x7a, 0xbb, 0x4c, 0xd8, 0xd5, 0xb9, + 0x65, 0x7f, 0x9b, 0xa5, 0x93, 0xa2, 0xe9, 0x4c, 0x51, 0xd0, 0xba, 0xd7, 0xa9, 0xbd, 0x6a, 0x99, + 0xed, 0xc2, 0xcf, 0x00, 0x33, 0x8d, 0x25, 0x8e, 0xcc, 0x8d, 0x25, 0xb2, 0x58, 0x5b, 0xbe, 0x58, + 0x7e, 0x85, 0xe3, 0xd4, 0xea, 0x08, 0x7c, 0x0f, 0xc4, 0x34, 0x53, 0x41, 0x97, 0x1d, 0xd4, 0xd4, + 0x08, 0x6a, 0xa6, 0x40, 0x86, 0xdb, 0x5b, 0x95, 0xa3, 0x9a, 0x29, 0x39, 0xa6, 0xc3, 0xb0, 0xb5, + 0x78, 0xc4, 0xab, 0x20, 0x88, 0x7a, 0x3b, 0xec, 0xc7, 0x20, 0xd4, 0x47, 0x26, 0x5d, 0x62, 0xf9, + 0xec, 0x02, 0xcb, 0xb2, 0x68, 0x10, 0xd9, 0x82, 0xc2, 0x47, 0x60, 0x45, 0x3d, 0x35, 0x89, 0xaa, + 0xb1, 0x75, 0xb7, 0x30, 0x8b, 0x03, 0x87, 0x3f, 0x04, 0x41, 0x03, 0xdb, 0x33, 0xbb, 0x38, 0x49, + 0xd0, 0xc0, 0xb0, 0x05, 0x62, 0x06, 0x56, 0x1e, 0x6b, 0xe4, 0x5c, 0xb9, 0x40, 0x04, 0xdb, 0x93, + 0x19, 0xc9, 0x4b, 0x8b, 0x31, 0xdd, 0x8d, 0x84, 0x0d, 0xaa, 0xbb, 0x97, 0x4b, 0x94, 0x81, 0x81, + 0x4f, 0x34, 0x72, 0x5e, 0x47, 0x04, 0x33, 0x29, 0x6f, 0x38, 0x10, 0xb6, 0x6e, 0xa0, 0xff, 0x7d, + 0x6b, 0x27, 0xc1, 0xd2, 0x05, 0x26, 0xc8, 0xd9, 0xd8, 0xf4, 0x03, 0x3c, 0x74, 0xaf, 0xbe, 0xd0, + 0x87, 0x5c, 0x7d, 0xf9, 0x60, 0x8a, 0x73, 0xaf, 0xbf, 0x63, 0xb0, 0x42, 0x9f, 0xcc, 0x54, 0xd8, + 0x9e, 0xb0, 0x4f, 0x67, 0x81, 0xa7, 0xef, 0xdb, 0x7c, 0xd8, 0x52, 0x49, 0x76, 0xc0, 0x87, 0xab, + 0xcf, 0x9d, 0x65, 0xfe, 0xeb, 0x30, 0x88, 0xb3, 0xd9, 0xa9, 0xa8, 0x5d, 0x55, 0x37, 0xe1, 0xef, + 0x38, 0x10, 0xd5, 0x35, 0xc3, 0x1d, 0x65, 0x6e, 0xde, 0x28, 0x2b, 0x16, 0xf7, 0xed, 0x48, 0xd8, + 0xf4, 0xa0, 0x1e, 0x60, 0x5d, 0x23, 0x48, 0xef, 0x90, 0xfe, 0x58, 0x27, 0xcf, 0xf1, 0x62, 0x13, + 0x0e, 0x74, 0xcd, 0x70, 0xe6, 0xfb, 0x37, 0x1c, 0x80, 0xba, 0x7a, 0xe9, 0x10, 0x29, 0x1d, 0xd4, + 0xd5, 0x70, 0x93, 0xdd, 0x22, 0x3b, 0x53, 0x53, 0x57, 0x60, 0x6f, 0x23, 0xb4, 0x4d, 0x6e, 0x47, + 0xc2, 0xee, 0x34, 0xd8, 0x97, 0x2b, 0xdb, 0xdf, 0xd3, 0x5e, 0xe2, 0x73, 0x6b, 0x2e, 0x13, 0xba, + 0x7a, 0xe9, 0xc8, 0x65, 0x9b, 0xe1, 0x5f, 0x39, 0x60, 0x17, 0xee, 0x0e, 0xa7, 0x2b, 0xdc, 0xdc, + 0xcb, 0xd8, 0x64, 0x39, 0x09, 0x33, 0xf1, 0xbe, 0xb4, 0x76, 0xc7, 0x12, 0x4e, 0x39, 0x2e, 0x26, + 0xe6, 0x86, 0xae, 0x19, 0xee, 0xd6, 0x60, 0xa5, 0x88, 0xcf, 0x43, 0x20, 0x56, 0xb7, 0x37, 0x0e, + 0x6b, 0x82, 0x5f, 0x01, 0xb6, 0x81, 0x1c, 0x81, 0xb9, 0x79, 0x02, 0x3f, 0x64, 0xc5, 0x6c, 0xfb, + 0x70, 0xbe, 0x22, 0x92, 0xbe, 0x85, 0xe7, 0x95, 0x35, 0x46, 0x6d, 0x4c, 0xd2, 0x33, 0xb0, 0xed, + 0xce, 0x94, 0xcf, 0xd9, 0x4c, 0x05, 0x6d, 0x4d, 0xf7, 0xde, 0x77, 0xe3, 0xd7, 0x3d, 0x54, 0xac, + 0xef, 0x37, 0x3b, 0x33, 0xce, 0x4c, 0xf8, 0x7b, 0x0e, 0x6c, 0x8f, 0xd5, 0xf4, 0xd7, 0x1b, 0x9a, + 0x57, 0x6f, 0x99, 0xd5, 0x7b, 0xef, 0x1d, 0x0c, 0xbe, 0xca, 0x79, 0x5a, 0xf9, 0x3b, 0x5c, 0xa9, + 0x06, 0x9b, 0xee, 0xa9, 0x37, 0x4b, 0x71, 0x14, 0x62, 0x1b, 0x9d, 0x7d, 0x33, 0xdf, 0x80, 0xe5, + 0x5f, 0xf6, 0x70, 0xb7, 0xa7, 0xdb, 0x5f, 0x49, 0x2c, 0x9f, 0x5f, 0xec, 0x0d, 0xf8, 0x76, 0x24, + 0x24, 0x28, 0x7e, 0x9c, 0xa0, 0xcc, 0x18, 0x61, 0x03, 0x44, 0xc8, 0x79, 0x17, 0x99, 0xe7, 0xb8, + 0x4d, 0x47, 0x2a, 0xb6, 0xd0, 0x7a, 0xa5, 0xf4, 0x1b, 0x2e, 0x85, 0x27, 0xc2, 0x98, 0x17, 0x0e, + 0x38, 0xb0, 0x66, 0xed, 0x5c, 0x65, 0x1c, 0x2a, 0x64, 0x87, 0x6a, 0x2c, 0x1c, 0x2a, 0xe5, 0xe7, + 0xf1, 0x49, 0xbe, 0xc9, 0x9a, 0xcd, 0xe7, 0x21, 0xca, 0x71, 0xcb, 0x50, 0x73, 0x93, 0x79, 0xc2, + 0x81, 0x8d, 0xf1, 0xb7, 0x32, 0xce, 0x28, 0x6c, 0x67, 0x54, 0x5e, 0x38, 0xa3, 0x8f, 0x67, 0x90, + 0x79, 0x64, 0x80, 0xee, 0xb1, 0x9b, 0x82, 0xf8, 0x17, 0x0e, 0x24, 0x67, 0xf5, 0x2e, 0xfc, 0x04, + 0xc4, 0xdd, 0x31, 0xb0, 0x62, 0xb0, 0x9f, 0x22, 0x31, 0xc7, 0x58, 0xeb, 0x77, 0xd0, 0xf4, 0xa0, + 0x06, 0xff, 0x7f, 0x83, 0x7a, 0xff, 0x3f, 0x1c, 0x00, 0x9e, 0x1f, 0x75, 0x0f, 0xc0, 0x76, 0xbd, + 0x5c, 0x93, 0x94, 0x72, 0xa5, 0x56, 0x2c, 0x97, 0x94, 0xaf, 0x4a, 0xd5, 0x8a, 0x74, 0x54, 0x3c, + 0x2e, 0x4a, 0x85, 0x44, 0x20, 0xbd, 0x3e, 0x18, 0x66, 0xa2, 0xd4, 0x51, 0xb2, 0xc2, 0x40, 0x11, + 0xac, 0x7b, 0xbd, 0xbf, 0x96, 0xaa, 0x09, 0x2e, 0x1d, 0x1f, 0x0c, 0x33, 0x11, 0xea, 0xf5, 0x35, + 0x32, 0xe1, 0x7d, 0xb0, 0xe1, 0xf5, 0xc9, 0xe5, 0xab, 0xb5, 0x5c, 0xb1, 0x94, 0x08, 0xa6, 0x3f, + 0x1a, 0x0c, 0x33, 0x71, 0xea, 0x97, 0x63, 0xaf, 0x17, 0x19, 0xb0, 0xe6, 0xf5, 0x2d, 0x95, 0x13, + 0xa1, 0x74, 0x6c, 0x30, 0xcc, 0xac, 0x52, 0xb7, 0x12, 0x86, 0x07, 0x20, 0xe5, 0xf7, 0x50, 0x4e, + 0x8a, 0xb5, 0x47, 0x4a, 0x5d, 0xaa, 0x95, 0x13, 0xe1, 0x74, 0x72, 0x30, 0xcc, 0x24, 0x1c, 0x5f, + 0xe7, 0x5d, 0x20, 0x1d, 0x7e, 0xfa, 0x07, 0x3e, 0x70, 0xff, 0xef, 0x41, 0xb0, 0xe6, 0xff, 0x45, + 0x01, 0xb3, 0xe0, 0x5b, 0x15, 0xb9, 0x5c, 0x29, 0x57, 0x73, 0x5f, 0x2a, 0xd5, 0x5a, 0xae, 0xf6, + 0x55, 0x75, 0xa2, 0x60, 0xbb, 0x14, 0xea, 0x5c, 0xd2, 0xda, 0xf0, 0x21, 0xe0, 0x27, 0xfd, 0x0b, + 0x52, 0xa5, 0x5c, 0x2d, 0xd6, 0x94, 0x8a, 0x24, 0x17, 0xcb, 0x85, 0x04, 0x97, 0xde, 0x1e, 0x0c, + 0x33, 0x1b, 0x14, 0xe2, 0xbf, 0x64, 0x7e, 0x00, 0x3e, 0x9e, 0x04, 0xd7, 0xcb, 0xb5, 0x62, 0xe9, + 0x27, 0x0e, 0x36, 0x98, 0xde, 0x1a, 0x0c, 0x33, 0x90, 0x62, 0x7d, 0x5d, 0xf4, 0x00, 0x6c, 0x4d, + 0x42, 0x2b, 0xb9, 0x6a, 0x55, 0x2a, 0x24, 0x42, 0xe9, 0xc4, 0x60, 0x98, 0x89, 0x51, 0x4c, 0x45, + 0x35, 0x4d, 0xd4, 0x84, 0x9f, 0x83, 0xd4, 0xa4, 0xb7, 0x2c, 0xfd, 0x54, 0x3a, 0xaa, 0x49, 0x85, + 0x44, 0x38, 0x0d, 0x07, 0xc3, 0xcc, 0x1a, 0xf5, 0x97, 0xd1, 0xcf, 0x51, 0x83, 0xa0, 0x99, 0xfc, + 0xc7, 0xb9, 0xe2, 0x97, 0x52, 0x21, 0xb1, 0xe4, 0xe5, 0x3f, 0x56, 0xb5, 0x36, 0x6a, 0x52, 0x39, + 0xf3, 0xa5, 0xab, 0x37, 0x7c, 0xe0, 0xd5, 0x1b, 0x3e, 0xf0, 0xe4, 0x9a, 0x0f, 0x5c, 0x5d, 0xf3, + 0xdc, 0xcb, 0x6b, 0x9e, 0xfb, 0xf7, 0x35, 0xcf, 0x3d, 0xbb, 0xe1, 0x03, 0x2f, 0x6f, 0xf8, 0xc0, + 0xab, 0x1b, 0x3e, 0xf0, 0xcd, 0xfb, 0xef, 0xb4, 0x4b, 0xfb, 0x3f, 0x26, 0xf6, 0xec, 0x9d, 0x2e, + 0xdb, 0x5d, 0xfe, 0x9d, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xba, 0x25, 0x63, 0x35, 0x4c, 0x11, + 0x00, 0x00, } func (this *TextProposal) Equal(that interface{}) bool { @@ -1148,6 +1153,20 @@ func (m *DepositParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.MinExpeditedDeposit) > 0 { + for iNdEx := len(m.MinExpeditedDeposit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MinExpeditedDeposit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGov(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } n7, err7 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxDepositPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxDepositPeriod):]) if err7 != nil { return 0, err7 @@ -1485,6 +1504,12 @@ func (m *DepositParams) Size() (n int) { } l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxDepositPeriod) n += 1 + l + sovGov(uint64(l)) + if len(m.MinExpeditedDeposit) > 0 { + for _, e := range m.MinExpeditedDeposit { + l = e.Size() + n += 1 + l + sovGov(uint64(l)) + } + } return n } @@ -2676,6 +2701,40 @@ func (m *DepositParams) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinExpeditedDeposit", 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 + } + m.MinExpeditedDeposit = append(m.MinExpeditedDeposit, types.Coin{}) + if err := m.MinExpeditedDeposit[len(m.MinExpeditedDeposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGov(dAtA[iNdEx:]) diff --git a/x/gov/types/params.go b/x/gov/types/params.go index 0a80e7e141c7..9f0792027682 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -21,11 +21,12 @@ const ( // Default governance params var ( - DefaultMinDepositTokens = sdk.NewInt(10000000) - DefaultQuorum = sdk.NewDecWithPrec(334, 3) - DefaultThreshold = sdk.NewDecWithPrec(5, 1) - DefaultExpeditedThreshold = sdk.NewDecWithPrec(667, 3) - DefaultVetoThreshold = sdk.NewDecWithPrec(334, 3) + DefaultMinDepositTokens = sdk.NewInt(10000000) + DefaultMinExpeditedDepositTokens = sdk.NewInt(10000000 * 5) + DefaultQuorum = sdk.NewDecWithPrec(334, 3) + DefaultThreshold = sdk.NewDecWithPrec(5, 1) + DefaultExpeditedThreshold = sdk.NewDecWithPrec(667, 3) + DefaultVetoThreshold = sdk.NewDecWithPrec(334, 3) DefaultProposalVotingPeriods []ProposalVotingPeriod = []ProposalVotingPeriod{} ) @@ -47,10 +48,11 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewDepositParams creates a new DepositParams object -func NewDepositParams(minDeposit sdk.Coins, maxDepositPeriod time.Duration) DepositParams { +func NewDepositParams(minDeposit sdk.Coins, maxDepositPeriod time.Duration, minExpeditedDeposit sdk.Coins) DepositParams { return DepositParams{ - MinDeposit: minDeposit, - MaxDepositPeriod: maxDepositPeriod, + MinDeposit: minDeposit, + MaxDepositPeriod: maxDepositPeriod, + MinExpeditedDeposit: minExpeditedDeposit, } } @@ -59,6 +61,7 @@ func DefaultDepositParams() DepositParams { return NewDepositParams( sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, DefaultMinDepositTokens)), DefaultPeriod, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, DefaultMinExpeditedDepositTokens)), ) } @@ -79,12 +82,20 @@ func validateDepositParams(i interface{}) error { return fmt.Errorf("invalid parameter type: %T", i) } - if !v.MinDeposit.IsValid() { - return fmt.Errorf("invalid minimum deposit: %s", v.MinDeposit) + minDeposit := v.MinDeposit + if !minDeposit.IsValid() { + return fmt.Errorf("invalid minimum deposit: %s", minDeposit) } if v.MaxDepositPeriod <= 0 { return fmt.Errorf("maximum deposit period must be positive: %d", v.MaxDepositPeriod) } + minExpeditedDeposit := v.MinExpeditedDeposit + if !minExpeditedDeposit.IsValid() { + return fmt.Errorf("invalid minimum expedited deposit: %s", minExpeditedDeposit) + } + if minExpeditedDeposit.IsAllLTE(minDeposit) { + return fmt.Errorf("minimum expedited deposit %s must be greater than expedited deposit %s", minExpeditedDeposit, minDeposit) + } return nil } diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index 57611fb1e74c..7087251f95da 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -81,6 +81,16 @@ func (p Proposal) GetTitle() string { return content.GetTitle() } +// GetMinDepositFromParams returns min expedited deposit from depositParams if +// the proposal is expedited. Otherwise, returns the regular min deposit from +// depositParams. +func (p Proposal) GetMinDepositFromParams(depositParams DepositParams) sdk.Coins { + if p.IsExpedited { + return depositParams.MinExpeditedDeposit + } + return depositParams.MinDeposit +} + // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (p Proposal) UnpackInterfaces(unpacker types.AnyUnpacker) error { var content Content diff --git a/x/gov/types/proposals_test.go b/x/gov/types/proposals_test.go index 7f6a2b23bfae..4d48344fbefd 100644 --- a/x/gov/types/proposals_test.go +++ b/x/gov/types/proposals_test.go @@ -3,7 +3,9 @@ package types import ( "fmt" "testing" + "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) @@ -22,3 +24,32 @@ func TestProposalStatus_Format(t *testing.T) { require.Equal(t, tt.expectedStringOutput, got) } } + +func TestProposalGetMinDepositFromParams(t *testing.T) { + testcases := []struct { + isExpedited bool + expectedMinDeposit sdk.Int + }{ + { + isExpedited: true, + expectedMinDeposit: DefaultMinExpeditedDepositTokens, + }, + { + isExpedited: false, + expectedMinDeposit: DefaultMinDepositTokens, + }, + } + + for _, tc := range testcases { + testProposal := NewTextProposal("test", "description") + + proposal, err := NewProposal(testProposal, 1, time.Now(), time.Now(), tc.isExpedited) + require.NoError(t, err) + + actualMinDeposit := proposal.GetMinDepositFromParams(DefaultDepositParams()) + + require.Equal(t, 1, len(actualMinDeposit)) + require.Equal(t, sdk.DefaultBondDenom, actualMinDeposit[0].Denom) + require.Equal(t, tc.expectedMinDeposit, actualMinDeposit[0].Amount) + } +} diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index f48b6ca3a3d5..3005418d7b80 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -64,17 +64,29 @@ func (suite *HandlerTestSuite) TestProposalHandler() { testProposal(proposal.ParamChange{ Subspace: govtypes.ModuleName, Key: string(govtypes.ParamStoreKeyDepositParams), - Value: `{"min_deposit": [{"denom": "uatom","amount": "64000000"}]}`, + Value: `{"min_deposit": [{"denom": "uatom","amount": "64000000"}],"min_expedited_deposit": [{"denom": "uatom","amount": "64000001"}]}`, }), func() { depositParams := suite.app.GovKeeper.GetDepositParams(suite.ctx) suite.Require().Equal(govtypes.DepositParams{ - MinDeposit: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(64000000))), - MaxDepositPeriod: govtypes.DefaultPeriod, + MinDeposit: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(64000000))), + MaxDepositPeriod: govtypes.DefaultPeriod, + MinExpeditedDeposit: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(64000001))), }, depositParams) }, false, }, + { + "min_deposit equals to min_expedited_deposit", + testProposal(proposal.ParamChange{ + Subspace: govtypes.ModuleName, + Key: string(govtypes.ParamStoreKeyDepositParams), + Value: `{"min_deposit": [{"denom": "uatom","amount": "64000000"}],"min_expedited_deposit": [{"denom": "uatom","amount": "64000000"}]}`, + }), + func() { + }, + true, + }, } for _, tc := range testCases { From 95389ce0e88be8aeb0157e46b78c692fdd978b38 Mon Sep 17 00:00:00 2001 From: John Letey Date: Wed, 22 Jun 2022 11:12:15 +0200 Subject: [PATCH 5/6] fix: still include custom voting periods --- x/gov/keeper/proposal.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 6b64bfeef5e3..5463f9a96dd3 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -194,7 +194,7 @@ func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) { func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) { proposal.VotingStartTime = ctx.BlockHeader().Time - votingPeriod := keeper.GetVotingParams(ctx).GetVotingPeriod(proposal.IsExpedited) + votingPeriod := keeper.GetVotingPeriod(ctx, proposal.GetContent(), proposal.IsExpedited) proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) proposal.Status = types.StatusVotingPeriod @@ -207,7 +207,7 @@ func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Propos // GetVotingPeriod returns the voting period for the given proposal Content. If // the proposal type has a custom voting period registered, we return that. // Otherwise, we use the default voting period. -func (keeper Keeper) GetVotingPeriod(ctx sdk.Context, content types.Content) time.Duration { +func (keeper Keeper) GetVotingPeriod(ctx sdk.Context, content types.Content, isExpedited bool) time.Duration { vpParams := keeper.GetVotingParams(ctx) // Check if there exists a registered custom voting period for the proposal @@ -219,7 +219,7 @@ func (keeper Keeper) GetVotingPeriod(ctx sdk.Context, content types.Content) tim } } - return vpParams.VotingPeriod + return vpParams.GetVotingPeriod(isExpedited) } func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) { From 73c31cbd2a816ad9d8702d3d6068e781e72526f6 Mon Sep 17 00:00:00 2001 From: John Letey Date: Fri, 24 Jun 2022 15:38:10 +0200 Subject: [PATCH 6/6] fix: fallback to custom voting periods --- x/gov/abci.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/gov/abci.go b/x/gov/abci.go index 8749fc7f685e..1359443d9930 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -52,7 +52,7 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { // 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 + // As a result, the deposits are either deleted or refunded in all cases // EXCEPT when an expedited proposal fails. if !(proposal.IsExpedited && !passes) { if burnDeposits { @@ -97,8 +97,8 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { // 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) + votingPeriod := keeper.GetVotingPeriod(ctx, proposal.GetContent(), proposal.IsExpedited) + proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)