Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gov): support v1.Proposal in v1beta1.Proposal.Content #14347

Merged
merged 12 commits into from
Dec 22, 2022
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
`cosmossdk.io/core/appmodule.AppModule` API via the new `NewManagerFromMap` constructor.
* [#14019](https://github.com/cosmos/cosmos-sdk/issues/14019) Remove the interface casting to allow other implementations of a `CommitMultiStore`.
* [#13881](https://github.com/cosmos/cosmos-sdk/pull/13881) Optimize iteration on nested cached KV stores and other operations in general.
* (x/gov) [#14347](https://github.com/cosmos/cosmos-sdk/pull/14347) Support `v1.Proposal` message in `v1beta1.Proposal.Content`.

### State Machine Breaking

Expand Down
14 changes: 13 additions & 1 deletion x/gov/migrations/v3/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
Expand All @@ -13,6 +14,7 @@ import (
// ConvertToLegacyProposal takes a new proposal and attempts to convert it to the
// legacy proposal format. This conversion is best effort. New proposal types that
// don't have a legacy message will return a "nil" content.
// Returns error when the amount of messages in `proposal` is different than one.
func ConvertToLegacyProposal(proposal v1.Proposal) (v1beta1.Proposal, error) {
var err error
legacyProposal := v1beta1.Proposal{
Expand Down Expand Up @@ -46,6 +48,9 @@ func ConvertToLegacyProposal(proposal v1.Proposal) (v1beta1.Proposal, error) {
if err != nil {
return v1beta1.Proposal{}, err
}
if len(msgs) != 1 {
return v1beta1.Proposal{}, sdkerrors.ErrInvalidType.Wrap("can't convert a gov/v1 Proposal to gov/v1beta1 Proposal when amount of proposal messages is more than one")
}
for _, msg := range msgs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The for loop isn't needed anymore

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes... too late :/ Is it worth to create another PR?

if legacyMsg, ok := msg.(*v1.MsgExecLegacyContent); ok {
// check that the content struct can be unmarshalled
Expand All @@ -54,9 +59,16 @@ func ConvertToLegacyProposal(proposal v1.Proposal) (v1beta1.Proposal, error) {
return v1beta1.Proposal{}, err
}
legacyProposal.Content = legacyMsg.Content
return legacyProposal, nil
}
}
return legacyProposal, nil
// hack to fill up the content with the first message
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
// this is to support clients that have not yet (properly) use gov/v1 endpoints
// https://github.com/cosmos/cosmos-sdk/issues/14334
// VerifyBasic assures that we have at least one message.
legacyProposal.Content, err = codectypes.NewAnyWithValue(msgs[0])

Copy link
Collaborator Author

@robert-zaremba robert-zaremba Dec 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first idea I had, was to create a simple message:

message BasicContent {
  string title = 1;
  string description = 2 ;
}

and fill it using the Content interface. But, then we will remove additional attributes, which are in fact used by explorers to display the full content (I verified that with ping pub).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, the current way you have is best imo.

return legacyProposal, err
}

func ConvertToLegacyTallyResult(tally *v1.TallyResult) (v1beta1.TallyResult, error) {
Expand Down
37 changes: 37 additions & 0 deletions x/gov/migrations/v3/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
v3 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v3"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -62,11 +64,46 @@ func TestConvertToLegacyProposal(t *testing.T) {
require.Equal(t, v1beta1Proposal.FinalTallyResult.No, sdk.NewInt(0))
require.Equal(t, v1beta1Proposal.FinalTallyResult.NoWithVeto, sdk.NewInt(0))
require.Equal(t, v1beta1Proposal.FinalTallyResult.Abstain, sdk.NewInt(0))
tp, ok := v1beta1Proposal.Content.GetCachedValue().(*v1beta1.TextProposal)
require.Truef(t, ok, "expected *TextProposal, got %T", v1beta1Proposal.Content.GetCachedValue())
require.Equal(t, tp.Title, "title")
require.Equal(t, tp.Description, "description")
}
})
}
}

func TestConvertToLegacyProposalContent(t *testing.T) {
msg := upgradetypes.MsgSoftwareUpgrade{Authority: "gov module", Plan: upgradetypes.Plan{Name: "test upgrade"}}
msgsAny, err := tx.SetMsgs([]sdk.Msg{&msg})
require.NoError(t, err)
tallyResult := v1.EmptyTallyResult()
proposal := v1.Proposal{
Id: 1,
Status: v1.StatusDepositPeriod,
Messages: msgsAny,
Metadata: "proposal metadata",
FinalTallyResult: &tallyResult,
}

legacyP, err := v3.ConvertToLegacyProposal(proposal)
require.NoError(t, err)
tp, ok := legacyP.Content.GetCachedValue().(*upgradetypes.MsgSoftwareUpgrade)
require.Truef(t, ok, "expected *MsgSoftwareUpgrade, got %T", legacyP.Content.GetCachedValue())
require.Equal(t, &msg, tp)

// more than one message is not supported
proposal.Messages, err = tx.SetMsgs([]sdk.Msg{&msg, &msg})
require.NoError(t, err)
_, err = v3.ConvertToLegacyProposal(proposal)
require.ErrorIs(t, sdkerrors.ErrInvalidType, err)

// zero messages is not supported
proposal.Messages = nil
_, err = v3.ConvertToLegacyProposal(proposal)
require.ErrorIs(t, sdkerrors.ErrInvalidType, err)
}

func TestConvertToLegacyTallyResult(t *testing.T) {
tallyResult := v1.EmptyTallyResult()
testCases := map[string]struct {
Expand Down