Skip to content

Commit

Permalink
feat: backport expedited proposals to v0.47.x
Browse files Browse the repository at this point in the history
Minimal backport of cosmos#14720
  • Loading branch information
johnletey committed Jun 9, 2023
1 parent fc2391b commit ed26611
Show file tree
Hide file tree
Showing 20 changed files with 1,424 additions and 508 deletions.
650 changes: 523 additions & 127 deletions api/cosmos/gov/v1/gov.pulsar.go

Large diffs are not rendered by default.

317 changes: 192 additions & 125 deletions api/cosmos/gov/v1/tx.pulsar.go

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions proto/cosmos/gov/v1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ message Proposal {
//
// Since: cosmos-sdk 0.47
string proposer = 13 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// expedited defines if the proposal is expedited
//
// Since: cosmos-sdk 0.50
bool expedited = 14;
}

// ProposalStatus enumerates the valid statuses of a proposal.
Expand Down Expand Up @@ -209,6 +214,19 @@ message Params {
// The ratio representing the proportion of the deposit value that must be paid at proposal submission.
string min_initial_deposit_ratio = 7 [(cosmos_proto.scalar) = "cosmos.Dec"];

// Duration of the voting period of an expedited proposal.
//
// Since: cosmos-sdk 0.50
google.protobuf.Duration expedited_voting_period = 10 [(gogoproto.stdduration) = true];

// Minimum proportion of Yes votes for proposal to pass. Default value: 0.67.
//
// Since: cosmos-sdk 0.50
string expedited_threshold = 11 [(cosmos_proto.scalar) = "cosmos.Dec"];

// Minimum expedited deposit for a proposal to enter voting period.
repeated cosmos.base.v1beta1.Coin expedited_min_deposit = 12 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];

// burn deposits if a proposal does not meet quorum
bool burn_vote_quorum = 13;

Expand Down
5 changes: 5 additions & 0 deletions proto/cosmos/gov/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ message MsgSubmitProposal {
//
// Since: cosmos-sdk 0.47
string summary = 6;

// expedited defines if the proposal is expedited or not
//
// Since: cosmos-sdk 0.50
bool expedited = 7;
}

// MsgSubmitProposalResponse defines the Msg/SubmitProposal response type.
Expand Down
42 changes: 34 additions & 8 deletions x/gov/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) {
logger.Info(
"proposal did not meet minimum deposit; deleted",
"proposal", proposal.Id,
"min_deposit", sdk.NewCoins(params.MinDeposit...).String(),
"expedited", proposal.Expedited,
"title", proposal.Title,
"min_deposit", sdk.NewCoins(proposal.GetMinDepositFromParams(keeper.GetParams(ctx))...).String(),
"total_deposit", sdk.NewCoins(proposal.TotalDeposit...).String(),
)

Expand All @@ -56,13 +58,22 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) {

passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal)

if burnDeposits {
keeper.DeleteAndBurnDeposits(ctx, proposal.Id)
} else {
keeper.RefundAndDeleteDeposits(ctx, proposal.Id)
// 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 cases
// EXCEPT when an expedited proposal fails.
if !(proposal.Expedited && !passes) {
if burnDeposits {
keeper.DeleteAndBurnDeposits(ctx, proposal.Id)
} else {
keeper.RefundAndDeleteDeposits(ctx, proposal.Id)
}
}

if passes {
keeper.RemoveFromActiveProposalQueue(ctx, proposal.Id, *proposal.VotingEndTime)

switch {
case passes:
var (
idx int
events sdk.Events
Expand Down Expand Up @@ -106,7 +117,21 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) {
tagValue = types.AttributeValueProposalFailed
logMsg = fmt.Sprintf("passed, but msg %d (%s) failed on execution: %s", idx, sdk.MsgTypeURL(msg), err)
}
} else {
case proposal.Expedited:
// 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.Expedited = false
params := keeper.GetParams(ctx)
endTime := proposal.VotingStartTime.Add(*params.VotingPeriod)
proposal.VotingEndTime = &endTime

keeper.InsertActiveProposalQueue(ctx, proposal.Id, *proposal.VotingEndTime)

tagValue = types.AttributeValueExpeditedProposalRejected
logMsg = "expedited proposal converted to regular"
default:
proposal.Status = v1.StatusRejected
tagValue = types.AttributeValueProposalRejected
logMsg = "rejected"
Expand All @@ -115,14 +140,15 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) {
proposal.FinalTallyResult = &tallyResults

keeper.SetProposal(ctx, proposal)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.Id, *proposal.VotingEndTime)

// when proposal become active
keeper.Hooks().AfterProposalVotingPeriodEnded(ctx, proposal.Id)

logger.Info(
"proposal tallied",
"proposal", proposal.Id,
"expedited", proposal.Expedited,
"title", proposal.Title,
"results", logMsg,
)

Expand Down
4 changes: 2 additions & 2 deletions x/gov/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,12 @@ metadata example:
return err
}

msgs, metadata, title, summary, deposit, err := parseSubmitProposal(clientCtx.Codec, args[0])
proposal, msgs, deposit, err := parseSubmitProposal(clientCtx.Codec, args[0])
if err != nil {
return err
}

msg, err := v1.NewMsgSubmitProposal(msgs, deposit, clientCtx.GetFromAddress().String(), metadata, title, summary)
msg, err := v1.NewMsgSubmitExpeditedProposal(msgs, deposit, clientCtx.GetFromAddress().String(), proposal.Metadata, proposal.Title, proposal.Summary, proposal.Expedited)
if err != nil {
return fmt.Errorf("invalid message: %w", err)
}
Expand Down
23 changes: 12 additions & 11 deletions x/gov/client/cli/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,44 +82,45 @@ func parseSubmitLegacyProposal(fs *pflag.FlagSet) (*legacyProposal, error) {
// proposal defines the new Msg-based proposal.
type proposal struct {
// Msgs defines an array of sdk.Msgs proto-JSON-encoded as Anys.
Messages []json.RawMessage `json:"messages,omitempty"`
Metadata string `json:"metadata"`
Deposit string `json:"deposit"`
Title string `json:"title"`
Summary string `json:"summary"`
Messages []json.RawMessage `json:"messages,omitempty"`
Metadata string `json:"metadata"`
Deposit string `json:"deposit"`
Title string `json:"title"`
Summary string `json:"summary"`
Expedited bool `json:"expedited"`
}

// parseSubmitProposal reads and parses the proposal.
func parseSubmitProposal(cdc codec.Codec, path string) ([]sdk.Msg, string, string, string, sdk.Coins, error) {
func parseSubmitProposal(cdc codec.Codec, path string) (proposal, []sdk.Msg, sdk.Coins, error) {
var proposal proposal

contents, err := os.ReadFile(path)
if err != nil {
return nil, "", "", "", nil, err
return proposal, nil, nil, err
}

err = json.Unmarshal(contents, &proposal)
if err != nil {
return nil, "", "", "", nil, err
return proposal, nil, nil, err
}

msgs := make([]sdk.Msg, len(proposal.Messages))
for i, anyJSON := range proposal.Messages {
var msg sdk.Msg
err := cdc.UnmarshalInterfaceJSON(anyJSON, &msg)
if err != nil {
return nil, "", "", "", nil, err
return proposal, nil, nil, err
}

msgs[i] = msg
}

deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit)
if err != nil {
return nil, "", "", "", nil, err
return proposal, nil, nil, err
}

return msgs, proposal.Metadata, proposal.Title, proposal.Summary, deposit, nil
return proposal, msgs, deposit, nil
}

// AddGovPropFlagsToCmd adds flags for defining MsgSubmitProposal fields.
Expand Down
16 changes: 9 additions & 7 deletions x/gov/client/cli/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,25 +163,26 @@ func TestParseSubmitProposal(t *testing.T) {
"metadata": "%s",
"title": "My awesome title",
"summary": "My awesome summary",
"deposit": "1000test"
"deposit": "1000test",
"expedited": true
}
`, addr, addr, addr, addr, addr, base64.StdEncoding.EncodeToString(expectedMetadata)))

badJSON := testutil.WriteToNewTempFile(t, "bad json")

// nonexistent json
_, _, _, _, _, err := parseSubmitProposal(cdc, "fileDoesNotExist") //nolint: dogsled
_, _, _, err := parseSubmitProposal(cdc, "fileDoesNotExist") //nolint: dogsled
require.Error(t, err)

// invalid json
_, _, _, _, _, err = parseSubmitProposal(cdc, badJSON.Name()) //nolint: dogsled
_, _, _, err = parseSubmitProposal(cdc, badJSON.Name()) //nolint: dogsled
require.Error(t, err)

// ok json
msgs, metadata, title, summary, deposit, err := parseSubmitProposal(cdc, okJSON.Name())
proposal, msgs, deposit, err := parseSubmitProposal(cdc, okJSON.Name())
require.NoError(t, err, "unexpected error")
require.Equal(t, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(1000))), deposit)
require.Equal(t, base64.StdEncoding.EncodeToString(expectedMetadata), metadata)
require.Equal(t, base64.StdEncoding.EncodeToString(expectedMetadata), proposal.Metadata)
require.Len(t, msgs, 3)
msg1, ok := msgs[0].(*banktypes.MsgSend)
require.True(t, ok)
Expand All @@ -200,8 +201,9 @@ func TestParseSubmitProposal(t *testing.T) {
require.True(t, ok)
require.Equal(t, "My awesome title", textProp.Title)
require.Equal(t, "My awesome description", textProp.Description)
require.Equal(t, "My awesome title", title)
require.Equal(t, "My awesome summary", summary)
require.Equal(t, "My awesome title", proposal.Title)
require.Equal(t, "My awesome summary", proposal.Summary)
require.Equal(t, true, proposal.Expedited)

err = okJSON.Close()
require.Nil(t, err, "unexpected error")
Expand Down
1 change: 1 addition & 0 deletions x/gov/migrations/v3/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func TestMigrateJSON(t *testing.T) {
"proposals": [
{
"deposit_end_time": "2001-09-09T01:46:40Z",
"expedited": false,
"final_tally_result": {
"abstain_count": "0",
"no_count": "0",
Expand Down
3 changes: 3 additions & 0 deletions x/gov/migrations/v4/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ func MigrateJSON(oldState *v1.GenesisState) (*v1.GenesisState, error) {

params := v1.NewParams(
oldState.DepositParams.MinDeposit,
defaultParams.ExpeditedMinDeposit,
*oldState.DepositParams.MaxDepositPeriod,
*oldState.VotingParams.VotingPeriod,
*defaultParams.ExpeditedVotingPeriod,
oldState.TallyParams.Quorum,
oldState.TallyParams.Threshold,
defaultParams.ExpeditedThreshold,
oldState.TallyParams.VetoThreshold,
defaultParams.MinInitialDepositRatio,
defaultParams.BurnProposalDepositPrevote,
Expand Down
8 changes: 8 additions & 0 deletions x/gov/migrations/v4/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ func TestMigrateJSON(t *testing.T) {
"burn_proposal_deposit_prevote": false,
"burn_vote_quorum": false,
"burn_vote_veto": true,
"expedited_min_deposit": [
{
"amount": "50000000",
"denom": "stake"
}
],
"expedited_threshold": "0.667000000000000000",
"expedited_voting_period": "86400s",
"max_deposit_period": "172800s",
"min_deposit": [
{
Expand Down
3 changes: 3 additions & 0 deletions x/gov/migrations/v4/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ func migrateParams(ctx sdk.Context, storeKey storetypes.StoreKey, legacySubspace
defaultParams := govv1.DefaultParams()
params := govv1.NewParams(
dp.MinDeposit,
defaultParams.ExpeditedMinDeposit,
*dp.MaxDepositPeriod,
*vp.VotingPeriod,
*defaultParams.ExpeditedVotingPeriod,
tp.Quorum,
tp.Threshold,
defaultParams.ExpeditedThreshold,
tp.VetoThreshold,
defaultParams.MinInitialDepositRatio,
defaultParams.BurnProposalDepositPrevote,
Expand Down
Loading

0 comments on commit ed26611

Please sign in to comment.