diff --git a/CHANGELOG.md b/CHANGELOG.md index c109bfce07ad..f3ddedd6f284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index 3b8d9f5a0872..f27d979ad363 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -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" ) @@ -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. diff --git a/x/genutil/migrations/v046/migrate.go b/x/genutil/migrations/v046/migrate.go new file mode 100644 index 000000000000..10a04fd5bd55 --- /dev/null +++ b/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 +} diff --git a/x/gov/keeper/migrations.go b/x/gov/keeper/migrations.go index 290e03cea5c6..9b87a5bcd062 100644 --- a/x/gov/keeper/migrations.go +++ b/x/gov/keeper/migrations.go @@ -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" ) @@ -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. +func (m Migrator) Migrate2to3(ctx sdk.Context) error { + return v046.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc) +} diff --git a/x/gov/migrations/v043/json_test.go b/x/gov/migrations/v043/json_test.go index abe85162429e..4202752aada6 100644 --- a/x/gov/migrations/v043/json_test.go +++ b/x/gov/migrations/v043/json_test.go @@ -2,7 +2,6 @@ package v043_test import ( "encoding/json" - "fmt" "testing" "github.com/stretchr/testify/require" @@ -122,7 +121,5 @@ func TestMigrateJSON(t *testing.T) { } }` - fmt.Println(string(indentedBz)) - require.Equal(t, expected, string(indentedBz)) } diff --git a/x/gov/migrations/v043/store.go b/x/gov/migrations/v043/store.go index 886279ac93eb..72658f39c268 100644 --- a/x/gov/migrations/v043/store.go +++ b/x/gov/migrations/v043/store.go @@ -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) diff --git a/x/gov/migrations/v046/migrate.go b/x/gov/migrations/v046/convert.go similarity index 50% rename from x/gov/migrations/v046/migrate.go rename to x/gov/migrations/v046/convert.go index 991e87376338..ae1c937808c8 100644 --- a/x/gov/migrations/v046/migrate.go +++ b/x/gov/migrations/v046/convert.go @@ -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" ) @@ -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 +} diff --git a/x/gov/migrations/v046/json.go b/x/gov/migrations/v046/json.go new file mode 100644 index 000000000000..7d92cd944e8c --- /dev/null +++ b/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 +} diff --git a/x/gov/migrations/v046/json_test.go b/x/gov/migrations/v046/json_test.go new file mode 100644 index 000000000000..655d2409a6c3 --- /dev/null +++ b/x/gov/migrations/v046/json_test.go @@ -0,0 +1,154 @@ +package v046_test + +import ( + "encoding/json" + "testing" + "time" + + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + v046 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v046" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2" +) + +func TestMigrateJSON(t *testing.T) { + encodingConfig := simapp.MakeTestEncodingConfig() + clientCtx := client.Context{}. + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithCodec(encodingConfig.Codec) + + voter, err := sdk.AccAddressFromBech32("cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh") + require.NoError(t, err) + + govGenState := v1beta1.DefaultGenesisState() + propTime := time.Unix(1e9, 0) + contentAny, err := codectypes.NewAnyWithValue(v1beta1.NewTextProposal("my title", "my desc").(proto.Message)) + require.NoError(t, err) + govGenState.Proposals = v1beta1.Proposals{ + v1beta1.Proposal{ + ProposalId: 1, + Content: contentAny, + SubmitTime: propTime, + DepositEndTime: propTime, + VotingStartTime: propTime, + VotingEndTime: propTime, + Status: v1beta1.StatusDepositPeriod, + FinalTallyResult: v1beta1.EmptyTallyResult(), + TotalDeposit: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(123))), + }, + } + govGenState.Votes = v1beta1.Votes{ + v1beta1.Vote{ProposalId: 1, Voter: voter.String(), Option: v1beta1.OptionAbstain}, + v1beta1.Vote{ProposalId: 2, Voter: voter.String(), Options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionNo)}, + } + + migrated, err := v046.MigrateJSON(govGenState) + require.NoError(t, err) + + // Make sure the migrated proposal's Msg signer is the gov acct. + require.Equal(t, + authtypes.NewModuleAddress(types.ModuleName).String(), + migrated.Proposals[0].Messages[0].GetCachedValue().(*v1beta2.MsgExecLegacyContent).Authority, + ) + + bz, err := clientCtx.Codec.MarshalJSON(migrated) + require.NoError(t, err) + + // Indent the JSON bz correctly. + var jsonObj map[string]interface{} + err = json.Unmarshal(bz, &jsonObj) + require.NoError(t, err) + indentedBz, err := json.MarshalIndent(jsonObj, "", "\t") + require.NoError(t, err) + + // Make sure about: + // - Proposals use MsgExecLegacyContent + expected := `{ + "deposit_params": { + "max_deposit_period": "172800s", + "min_deposit": [ + { + "amount": "10000000", + "denom": "stake" + } + ] + }, + "deposits": [], + "proposals": [ + { + "deposit_end_time": "2001-09-09T01:46:40Z", + "final_tally_result": { + "abstain": "0", + "no": "0", + "no_with_veto": "0", + "yes": "0" + }, + "messages": [ + { + "@type": "/cosmos.gov.v1beta2.MsgExecLegacyContent", + "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn", + "content": { + "@type": "/cosmos.gov.v1beta1.TextProposal", + "description": "my desc", + "title": "my title" + } + } + ], + "metadata": null, + "proposal_id": "1", + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "submit_time": "2001-09-09T01:46:40Z", + "total_deposit": [ + { + "amount": "123", + "denom": "stake" + } + ], + "voting_end_time": "2001-09-09T01:46:40Z", + "voting_start_time": "2001-09-09T01:46:40Z" + } + ], + "starting_proposal_id": "1", + "tally_params": { + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000" + }, + "votes": [ + { + "options": [ + { + "option": "VOTE_OPTION_ABSTAIN", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "1", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "options": [ + { + "option": "VOTE_OPTION_NO", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "2", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + } + ], + "voting_params": { + "voting_period": "172800s" + } +}` + + require.Equal(t, expected, string(indentedBz)) +} diff --git a/x/gov/migrations/v046/keys.go b/x/gov/migrations/v046/keys.go new file mode 100644 index 000000000000..aaf810f3b00d --- /dev/null +++ b/x/gov/migrations/v046/keys.go @@ -0,0 +1,6 @@ +package v046 + +const ( + // ModuleName is the name of the module + ModuleName = "gov" +) diff --git a/x/gov/migrations/v046/store.go b/x/gov/migrations/v046/store.go new file mode 100644 index 000000000000..20f367fedeb0 --- /dev/null +++ b/x/gov/migrations/v046/store.go @@ -0,0 +1,51 @@ +package v046 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + v040 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v040" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +// migrateProposals migrates all legacy proposals into MsgExecLegacyContent +// proposals. +func migrateProposals(store sdk.KVStore, cdc codec.BinaryCodec) error { + propStore := prefix.NewStore(store, v040.ProposalsKeyPrefix) + + iter := propStore.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + var oldProp v1beta1.Proposal + err := cdc.Unmarshal(iter.Value(), &oldProp) + if err != nil { + return err + } + + newProp, err := convertToNewProposal(oldProp) + if err != nil { + return err + } + bz, err := cdc.Marshal(&newProp) + if err != nil { + return err + } + + // Set new value on store. + propStore.Set(iter.Key(), bz) + } + + return nil +} + +// MigrateStore performs in-place store migrations from v0.43 to v0.46. The +// migration includes: +// +// - Migrate proposals to be Msg-based. +func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec) error { + store := ctx.KVStore(storeKey) + + return migrateProposals(store, cdc) +} diff --git a/x/gov/migrations/v046/store_test.go b/x/gov/migrations/v046/store_test.go new file mode 100644 index 000000000000..d392a9d72d3f --- /dev/null +++ b/x/gov/migrations/v046/store_test.go @@ -0,0 +1,76 @@ +package v046_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + v040gov "github.com/cosmos/cosmos-sdk/x/gov/migrations/v040" + v046gov "github.com/cosmos/cosmos-sdk/x/gov/migrations/v046" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +func TestMigrateStore(t *testing.T) { + cdc := simapp.MakeTestEncodingConfig().Codec + govKey := sdk.NewKVStoreKey("gov") + ctx := testutil.DefaultContext(govKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(govKey) + + propTime := time.Unix(1e9, 0) + + // Create 2 proposals + prop1, err := v1beta1.NewProposal(v1beta1.NewTextProposal("my title 1", "my desc 1"), 1, propTime, propTime) + require.NoError(t, err) + prop1Bz, err := cdc.Marshal(&prop1) + require.NoError(t, err) + prop2, err := v1beta1.NewProposal(upgradetypes.NewSoftwareUpgradeProposal("my title 2", "my desc 2", upgradetypes.Plan{ + Name: "my plan 2", + }), 2, propTime, propTime) + require.NoError(t, err) + prop2Bz, err := cdc.Marshal(&prop2) + require.NoError(t, err) + + store.Set(v040gov.ProposalKey(prop1.ProposalId), prop1Bz) + store.Set(v040gov.ProposalKey(prop2.ProposalId), prop2Bz) + + // Run migrations. + err = v046gov.MigrateStore(ctx, govKey, cdc) + require.NoError(t, err) + + var newProp1 v1beta2.Proposal + err = cdc.Unmarshal(store.Get(v040gov.ProposalKey(prop1.ProposalId)), &newProp1) + require.NoError(t, err) + compareProps(t, prop1, newProp1) + + var newProp2 v1beta2.Proposal + err = cdc.Unmarshal(store.Get(v040gov.ProposalKey(prop2.ProposalId)), &newProp2) + require.NoError(t, err) + compareProps(t, prop2, newProp2) +} + +func compareProps(t *testing.T, oldProp v1beta1.Proposal, newProp v1beta2.Proposal) { + require.Equal(t, oldProp.ProposalId, newProp.ProposalId) + require.Equal(t, oldProp.TotalDeposit.String(), sdk.Coins(newProp.TotalDeposit).String()) + require.Equal(t, oldProp.Status.String(), newProp.Status.String()) + require.Equal(t, oldProp.FinalTallyResult.Yes.String(), newProp.FinalTallyResult.Yes) + require.Equal(t, oldProp.FinalTallyResult.No.String(), newProp.FinalTallyResult.No) + require.Equal(t, oldProp.FinalTallyResult.NoWithVeto.String(), newProp.FinalTallyResult.NoWithVeto) + require.Equal(t, oldProp.FinalTallyResult.Abstain.String(), newProp.FinalTallyResult.Abstain) + + newContent := newProp.Messages[0].GetCachedValue().(*v1beta2.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content) + require.Equal(t, oldProp.Content.GetCachedValue().(v1beta1.Content), newContent) + + // Compare UNIX times, as a simple Equal gives difference between Local and + // UTC times. + // ref: https://github.com/golang/go/issues/19486#issuecomment-292968278 + require.Equal(t, oldProp.SubmitTime.Unix(), newProp.SubmitTime.Unix()) + require.Equal(t, oldProp.DepositEndTime.Unix(), newProp.DepositEndTime.Unix()) + require.Equal(t, oldProp.VotingStartTime.Unix(), newProp.VotingStartTime.Unix()) + require.Equal(t, oldProp.VotingEndTime.Unix(), newProp.VotingEndTime.Unix()) +} diff --git a/x/gov/module.go b/x/gov/module.go index d3ce2703d09c..4b8fc83772a1 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -169,6 +169,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err != nil { panic(err) } + err = cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3) + if err != nil { + panic(err) + } } // InitGenesis performs genesis initialization for the gov module. It returns @@ -188,7 +192,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 2 } +func (AppModule) ConsensusVersion() uint64 { return 3 } // BeginBlock performs a no-op. func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}