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

fix(gov): Fix v3 votes migrations #14214

Merged
merged 11 commits into from
Dec 13, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### State Machine Breaking

* (x/gov) [#14214](https://github.com/cosmos/cosmos-sdk/pull/14214) Fix gov v0.46 migration to v1 votes.
* (x/group) [#13742](https://github.com/cosmos/cosmos-sdk/pull/13742) Migrate group policy account from module accounts to base account.
* (x/group) [#14071](https://github.com/cosmos/cosmos-sdk/pull/14071) Don't re-tally proposal after voting period end if they have been marked as ACCEPTED or REJECTED.
* (codec) [#13307](https://github.com/cosmos/cosmos-sdk/pull/13307) Register all modules' `Msg`s with group's ModuleCdc so that Amino sign bytes are correctly generated.
Expand Down
5 changes: 2 additions & 3 deletions x/gov/migrations/v3/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)

var voter = sdk.MustAccAddressFromBech32("cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh")

func TestMigrateJSON(t *testing.T) {
encodingConfig := moduletestutil.MakeTestEncodingConfig(gov.AppModuleBasic{})
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))
Expand Down
48 changes: 46 additions & 2 deletions x/gov/migrations/v3/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
v1 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v1"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)

// migrateProposals migrates all legacy proposals into MsgExecLegacyContent
Expand All @@ -18,7 +19,7 @@ func migrateProposals(store sdk.KVStore, cdc codec.BinaryCodec) error {
defer iter.Close()

for ; iter.Valid(); iter.Next() {
var oldProp v1beta1.Proposal
var oldProp govv1beta1.Proposal
err := cdc.Unmarshal(iter.Value(), &oldProp)
if err != nil {
return err
Expand All @@ -40,12 +41,55 @@ func migrateProposals(store sdk.KVStore, cdc codec.BinaryCodec) error {
return nil
}

// migrateVotes migrates all v1beta1 weighted votes (with sdk.Dec as weight)
// to v1 weighted votes (with string as weight)
func migrateVotes(store sdk.KVStore, cdc codec.BinaryCodec) error {
votesStore := prefix.NewStore(store, v1.VotesKeyPrefix)

iter := votesStore.Iterator(nil, nil)
defer iter.Close()

for ; iter.Valid(); iter.Next() {
var oldVote govv1beta1.Vote
err := cdc.Unmarshal(iter.Value(), &oldVote)
if err != nil {
return err
}

newVote := govv1.Vote{
ProposalId: oldVote.ProposalId,
Voter: oldVote.Voter,
}
newOptions := make([]*govv1.WeightedVoteOption, len(oldVote.Options))
for i, o := range oldVote.Options {
newOptions[i] = &govv1.WeightedVoteOption{
Option: govv1.VoteOption(o.Option),
Weight: o.Weight.String(), // Convert to decimal string
}
}
newVote.Options = newOptions
bz, err := cdc.Marshal(&newVote)
if err != nil {
return err
}

// Set new value on store.
votesStore.Set(iter.Key(), bz)
}

return nil
}

// MigrateStore performs in-place store migrations from v2 (v0.43) to v3 (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)

if err := migrateVotes(store, cdc); err != nil {
return err
}

return migrateProposals(store, cdc)
}
17 changes: 17 additions & 0 deletions x/gov/migrations/v3/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ func TestMigrateStore(t *testing.T) {
store.Set(v1gov.ProposalKey(prop1.ProposalId), prop1Bz)
store.Set(v1gov.ProposalKey(prop2.ProposalId), prop2Bz)

// Vote on prop 1
options := []v1beta1.WeightedVoteOption{
{Option: v1beta1.OptionNo, Weight: sdk.MustNewDecFromStr("0.3")},
{Option: v1beta1.OptionYes, Weight: sdk.MustNewDecFromStr("0.7")},
}
vote1 := v1beta1.NewVote(1, voter, options)
vote1Bz := cdc.MustMarshal(&vote1)
store.Set(v1gov.VoteKey(1, voter), vote1Bz)

// Run migrations.
err = v3gov.MigrateStore(ctx, govKey, cdc)
require.NoError(t, err)
Expand All @@ -54,6 +63,14 @@ func TestMigrateStore(t *testing.T) {
err = cdc.Unmarshal(store.Get(v1gov.ProposalKey(prop2.ProposalId)), &newProp2)
require.NoError(t, err)
compareProps(t, prop2, newProp2)

var newVote1 v1.Vote
err = cdc.Unmarshal(store.Get(v1gov.VoteKey(prop1.ProposalId, voter)), &newVote1)
require.NoError(t, err)
// Without the votes migration, we would have 300000000000000000 in state,
// because of how sdk.Dec stores itself in state.
require.Equal(t, "0.300000000000000000", newVote1.Options[0].Weight)
require.Equal(t, "0.700000000000000000", newVote1.Options[1].Weight)
}

func compareProps(t *testing.T, oldProp v1beta1.Proposal, newProp v1.Proposal) {
Expand Down