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: Add x/gov v043->v046 migrations #11036

Merged
merged 15 commits into from Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -60,6 +60,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#11019](https://github.com/cosmos/cosmos-sdk/pull/11019) Add `MsgCreatePermanentLockedAccount` and CLI method for creating permanent locked account
* [\#10947](https://github.com/cosmos/cosmos-sdk/pull/10947) Add `AllowancesByGranter` query to the feegrant module
* [\#10407](https://github.com/cosmos/cosmos-sdk/pull/10407) Add validation to `x/upgrade` module's `BeginBlock` to check accidental binary downgrades
* (gov) [\#11036](https://github.com/cosmos/cosmos-sdk/pull/11036) Add in-place migrations for 0.43->0.46. Add a `migrate v0.46` CLI command for v0.43->0.46 JSON genesis migration.

### API Breaking Changes

Expand Down
4 changes: 3 additions & 1 deletion x/genutil/client/cli/migrate.go
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/version"
v040 "github.com/cosmos/cosmos-sdk/x/genutil/migrations/v040"
v043 "github.com/cosmos/cosmos-sdk/x/genutil/migrations/v043"
v046 "github.com/cosmos/cosmos-sdk/x/genutil/migrations/v046"
"github.com/cosmos/cosmos-sdk/x/genutil/types"
)

Expand All @@ -26,7 +27,8 @@ const flagGenesisTime = "genesis-time"
// Ref: https://github.com/cosmos/cosmos-sdk/issues/5041
var migrationMap = types.MigrationMap{
"v0.42": v040.Migrate, // NOTE: v0.40, v0.41 and v0.42 are genesis compatible.
"v0.43": v043.Migrate,
"v0.43": v043.Migrate, // NOTE: v0.43, v0.44 and v0.45 are genesis compatible.
"v0.46": v046.Migrate,
}

// GetMigrationCallback returns a MigrationCallback for a given version.
Expand Down
32 changes: 32 additions & 0 deletions x/genutil/migrations/v046/migrate.go
@@ -0,0 +1,32 @@
package v046

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/genutil/types"
v043gov "github.com/cosmos/cosmos-sdk/x/gov/migrations/v043"
v046gov "github.com/cosmos/cosmos-sdk/x/gov/migrations/v046"
gov "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)

// Migrate migrates exported state from v0.43 to a v0.46 genesis state.
func Migrate(appState types.AppMap, clientCtx client.Context) types.AppMap {
// Migrate x/gov.
if appState[v043gov.ModuleName] != nil {
// unmarshal relative source genesis application state
var oldGovState gov.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appState[v043gov.ModuleName], &oldGovState)

// delete deprecated x/gov genesis state
delete(appState, v043gov.ModuleName)

// Migrate relative source genesis application state and marshal it into
// the respective key.
newGovState, err := v046gov.MigrateJSON(&oldGovState)
if err != nil {
panic(err)
}
appState[v046gov.ModuleName] = clientCtx.Codec.MustMarshalJSON(newGovState)
}

return appState
}
6 changes: 6 additions & 0 deletions x/gov/keeper/migrations.go
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
v046 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v046"
v043 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v043"
)

Expand All @@ -19,3 +20,8 @@ func NewMigrator(keeper Keeper) Migrator {
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v043.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}

// Migrate2to3 migrates from version 2 to 3.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we use 1, 2, and 3 version numbers - do they relate to anything. Might it be more intuitive to specify SDK version migrations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We decided in adr-041 to use uint here. I guess the idea back then was to prepare when modules will have their own go.mods. It might be that this ConsensusVersion == the major version in go.mod. Or not. Anyways, I think it's better for modules to have independent consensus versions than be tied up to SDK versions.

(note the v04* migration folders could probably be renamed though).

func (m Migrator) Migrate2to3(ctx sdk.Context) error {
return v046.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}
3 changes: 0 additions & 3 deletions x/gov/migrations/v043/json_test.go
Expand Up @@ -2,7 +2,6 @@ package v043_test

import (
"encoding/json"
"fmt"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -122,7 +121,5 @@ func TestMigrateJSON(t *testing.T) {
}
}`

fmt.Println(string(indentedBz))

require.Equal(t, expected, string(indentedBz))
}
1 change: 1 addition & 0 deletions x/gov/migrations/v043/store.go
Expand Up @@ -75,6 +75,7 @@ func migrateStoreWeightedVotes(store sdk.KVStore, cdc codec.BinaryCodec) error {
// migration includes:
//
// - Change addresses to be length-prefixed.
// - Change all legacy votes to ADR-037 weighted votes.
func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec) error {
store := ctx.KVStore(storeKey)
migratePrefixProposalAddress(store, types.DepositsKeyPrefix)
Expand Down
108 changes: 108 additions & 0 deletions x/gov/migrations/v046/migrate.go → x/gov/migrations/v046/convert.go
Expand Up @@ -3,7 +3,9 @@ package v046
import (
"fmt"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
)
Expand Down Expand Up @@ -117,3 +119,109 @@ func ConvertToLegacyDeposit(deposit *v1beta2.Deposit) v1beta1.Deposit {
Amount: types.NewCoins(deposit.Amount...),
}
}

func convertToNewDeposits(oldDeps v1beta1.Deposits) v1beta2.Deposits {
newDeps := make([]*v1beta2.Deposit, len(oldDeps))
for i, oldDep := range oldDeps {
newDeps[i] = &v1beta2.Deposit{
ProposalId: oldDep.ProposalId,
Depositor: oldDep.Depositor,
Amount: oldDep.Amount,
}
}

return newDeps
}

func convertToNewVotes(oldVotes v1beta1.Votes) (v1beta2.Votes, error) {
newVotes := make([]*v1beta2.Vote, len(oldVotes))
for i, oldVote := range oldVotes {
var newWVOs []*v1beta2.WeightedVoteOption

// We deprecated Vote.Option in v043. However, it might still be set.
// - if only Options is set, or both Option & Options are set, we read from Options,
// - if Options is not set, and Option is set, we read from Option,
// - if none are set, we throw error.
if oldVote.Options != nil {
newWVOs = make([]*v1beta2.WeightedVoteOption, len(oldVote.Options))
for j, oldWVO := range oldVote.Options {
newWVOs[j] = v1beta2.NewWeightedVoteOption(v1beta2.VoteOption(oldWVO.Option), oldWVO.Weight)
}
} else if oldVote.Option != v1beta1.OptionEmpty {
newWVOs = v1beta2.NewNonSplitVoteOption(v1beta2.VoteOption(oldVote.Option))
} else {
return nil, fmt.Errorf("vote does not have neither Options nor Option")
}

newVotes[i] = &v1beta2.Vote{
ProposalId: oldVote.ProposalId,
Voter: oldVote.Voter,
Options: newWVOs,
}
}

return newVotes, nil
}

func convertToNewDepParams(oldDepParams v1beta1.DepositParams) v1beta2.DepositParams {
return v1beta2.DepositParams{
MinDeposit: oldDepParams.MinDeposit,
MaxDepositPeriod: &oldDepParams.MaxDepositPeriod,
}
}

func convertToNewVotingParams(oldVoteParams v1beta1.VotingParams) v1beta2.VotingParams {
return v1beta2.VotingParams{
VotingPeriod: &oldVoteParams.VotingPeriod,
}
}

func convertToNewTallyParams(oldTallyParams v1beta1.TallyParams) v1beta2.TallyParams {
return v1beta2.TallyParams{
Quorum: oldTallyParams.Quorum.String(),
Threshold: oldTallyParams.Threshold.String(),
VetoThreshold: oldTallyParams.VetoThreshold.String(),
}
}

func convertToNewProposal(oldProp v1beta1.Proposal) (v1beta2.Proposal, error) {
msg, err := v1beta2.NewLegacyContent(oldProp.GetContent(), authtypes.NewModuleAddress(ModuleName).String())
if err != nil {
return v1beta2.Proposal{}, err
}
msgAny, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return v1beta2.Proposal{}, err
}

return v1beta2.Proposal{
ProposalId: oldProp.ProposalId,
Messages: []*codectypes.Any{msgAny},
Status: v1beta2.ProposalStatus(oldProp.Status),
FinalTallyResult: &v1beta2.TallyResult{
Yes: oldProp.FinalTallyResult.Yes.String(),
No: oldProp.FinalTallyResult.No.String(),
Abstain: oldProp.FinalTallyResult.Abstain.String(),
NoWithVeto: oldProp.FinalTallyResult.NoWithVeto.String(),
},
SubmitTime: &oldProp.SubmitTime,
DepositEndTime: &oldProp.DepositEndTime,
TotalDeposit: oldProp.TotalDeposit,
VotingStartTime: &oldProp.VotingStartTime,
VotingEndTime: &oldProp.VotingEndTime,
}, nil
}

func convertToNewProposals(oldProps v1beta1.Proposals) (v1beta2.Proposals, error) {
newProps := make([]*v1beta2.Proposal, len(oldProps))
for i, oldProp := range oldProps {
p, err := convertToNewProposal(oldProp)
if err != nil {
return nil, err
}

newProps[i] = &p
}

return newProps, nil
}
34 changes: 34 additions & 0 deletions x/gov/migrations/v046/json.go
@@ -0,0 +1,34 @@
package v046

import (
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
)

// MigrateJSON accepts exported v0.43 x/gov genesis state and migrates it to
// v0.46 x/gov genesis state. The migration includes:
//
// - Updating everything to v1beta2.
// - Migrating proposals to be Msg-based.
func MigrateJSON(oldState *v1beta1.GenesisState) (*v1beta2.GenesisState, error) {
newProps, err := convertToNewProposals(oldState.Proposals)
if err != nil {
return nil, err
}
newVotes, err := convertToNewVotes(oldState.Votes)
if err != nil {
return nil, err
}

depParams, votingParms, tallyParams := convertToNewDepParams(oldState.DepositParams), convertToNewVotingParams(oldState.VotingParams), convertToNewTallyParams(oldState.TallyParams)

return &v1beta2.GenesisState{
StartingProposalId: oldState.StartingProposalId,
Deposits: convertToNewDeposits(oldState.Deposits),
Votes: newVotes,
Proposals: newProps,
DepositParams: &depParams,
VotingParams: &votingParms,
TallyParams: &tallyParams,
}, nil
}