diff --git a/CHANGELOG.md b/CHANGELOG.md index 551ab5614ebf..628ee735fb57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#8346](https://github.com/cosmos/cosmos-sdk/pull/8346) All CLI `tx` commands generate ServiceMsgs by default. Graceful Amino support has been added to ServiceMsgs to support signing legacy Msgs. * (crypto/ed25519) [\#8690] Adopt zip1215 ed2559 verification rules. * [\#8849](https://github.com/cosmos/cosmos-sdk/pull/8849) Upgrade module no longer supports time based upgrades. +* [\#8880](https://github.com/cosmos/cosmos-sdk/pull/8880) The CLI `simd migrate v0.40 ...` command has been renamed to `simd migrate v0.42`. ### API Breaking Changes diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index 483f4aaf107d..9bba5c3d8845 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -18,6 +18,7 @@ import ( v038 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v038" v039 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v039" v040 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v040" + v043 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v043" "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -28,9 +29,10 @@ const flagGenesisTime = "genesis-time" // Ref: https://github.com/cosmos/cosmos-sdk/issues/5041 var migrationMap = types.MigrationMap{ "v0.36": v036.Migrate, - "v0.38": v038.Migrate, // NOTE: v0.37 and v0.38 are genesis compatible + "v0.38": v038.Migrate, // NOTE: v0.37 and v0.38 are genesis compatible. "v0.39": v039.Migrate, - "v0.40": v040.Migrate, + "v0.42": v040.Migrate, // NOTE: v0.40, v0.41 and v0.42 are genesis compatible. + "v0.43": v043.Migrate, } // GetMigrationCallback returns a MigrationCallback for a given version. @@ -131,7 +133,7 @@ $ %s migrate v0.36 /path/to/genesis.json --chain-id=cosmoshub-3 --genesis-time=2 return errors.Wrap(err, "failed to sort JSON genesis doc") } - fmt.Println(string(sortedBz)) + cmd.Println(string(sortedBz)) return nil }, } diff --git a/x/genutil/client/cli/migrate_test.go b/x/genutil/client/cli/migrate_test.go index d31f8962a958..7e2f0e17af5f 100644 --- a/x/genutil/client/cli/migrate_test.go +++ b/x/genutil/client/cli/migrate_test.go @@ -25,35 +25,41 @@ func (s *IntegrationTestSuite) TestMigrateGenesis() { target string expErr bool expErrMsg string + check func(jsonOut string) }{ { - "migrate to 0.36", + "migrate 0.34 to 0.36", `{"chain_id":"test","app_state":{}}`, "v0.36", - false, "", + false, "", func(_ string) {}, }, { - "exported 0.37 genesis file", + "migrate 0.37 to 0.42", v037Exported, - "v0.40", - true, "Make sure that you have correctly migrated all Tendermint consensus params", + "v0.42", + true, "Make sure that you have correctly migrated all Tendermint consensus params", func(_ string) {}, }, { - "valid 0.40 genesis file", + "migrate 0.42 to 0.43", v040Valid, - "v0.40", + "v0.43", false, "", + func(jsonOut string) { + // Make sure the json output contains the ADR-037 gov weighted votes. + s.Require().Contains(jsonOut, "\"weight\":\"1.000000000000000000\"") + }, }, } for _, tc := range testCases { s.Run(tc.name, func() { genesisFile := testutil.WriteToNewTempFile(s.T(), tc.genesis) - _, err := clitestutil.ExecTestCLICmd(val0.ClientCtx, cli.MigrateGenesisCmd(), []string{tc.target, genesisFile.Name()}) + jsonOutput, err := clitestutil.ExecTestCLICmd(val0.ClientCtx, cli.MigrateGenesisCmd(), []string{tc.target, genesisFile.Name()}) if tc.expErr { s.Require().Contains(err.Error(), tc.expErrMsg) } else { s.Require().NoError(err) + tc.check(jsonOutput.String()) } }) } diff --git a/x/genutil/client/cli/validate_genesis_test.go b/x/genutil/client/cli/validate_genesis_test.go index f62aa1b7a48e..ea3d49c47465 100644 --- a/x/genutil/client/cli/validate_genesis_test.go +++ b/x/genutil/client/cli/validate_genesis_test.go @@ -26,9 +26,28 @@ var v037Exported = `{ }` // An example exported genesis file that's 0.40 compatible. +// We added the following app_state: +// +// - x/gov: added votes to test ADR-037 split votes migration. var v040Valid = `{ "app_hash": "", - "app_state": {}, + "app_state": { + "gov": { + "starting_proposal_id": "0", + "deposits": [], + "votes": [ + { + "proposal_id": "5", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + "option": "VOTE_OPTION_YES" + } + ], + "proposals": [], + "deposit_params": { "min_deposit": [], "max_deposit_period": "0s" }, + "voting_params": { "voting_period": "0s" }, + "tally_params": { "quorum": "0", "threshold": "0", "veto_threshold": "0" } + } + }, "chain_id": "test", "consensus_params": { "block": { diff --git a/x/genutil/legacy/v043/migrate.go b/x/genutil/legacy/v043/migrate.go new file mode 100644 index 000000000000..8b6a00529252 --- /dev/null +++ b/x/genutil/legacy/v043/migrate.go @@ -0,0 +1,27 @@ +package v043 + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/x/genutil/types" + v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040" + v043gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v043" +) + +// Migrate migrates exported state from v0.40 to a v0.43 genesis state. +func Migrate(appState types.AppMap, clientCtx client.Context) types.AppMap { + // Migrate x/gov. + if appState[v040gov.ModuleName] != nil { + // unmarshal relative source genesis application state + var oldGovState v040gov.GenesisState + clientCtx.JSONMarshaler.MustUnmarshalJSON(appState[v040gov.ModuleName], &oldGovState) + + // delete deprecated x/gov genesis state + delete(appState, v040gov.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v043gov.ModuleName] = clientCtx.JSONMarshaler.MustMarshalJSON(v043gov.MigrateJSON(&oldGovState)) + } + + return appState +} diff --git a/x/gov/legacy/v040/genesis.pb.go b/x/gov/legacy/v040/genesis.pb.go new file mode 100644 index 000000000000..2dc67061a936 --- /dev/null +++ b/x/gov/legacy/v040/genesis.pb.go @@ -0,0 +1,592 @@ +// Package v040 is taken from: +// https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/gov/types/genesis.pb.go +// by copy-pasted only the relevants parts for Genesis. +//nolint +package v040 + +import ( + fmt "fmt" + io "io" + math_bits "math/bits" + + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + + "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +// GenesisState defines the gov module's genesis state. +type GenesisState struct { + // starting_proposal_id is the ID of the starting proposal. + StartingProposalId uint64 `protobuf:"varint,1,opt,name=starting_proposal_id,json=startingProposalId,proto3" json:"starting_proposal_id,omitempty" yaml:"starting_proposal_id"` + // deposits defines all the deposits present at genesis. + Deposits types.Deposits `protobuf:"bytes,2,rep,name=deposits,proto3,castrepeated=Deposits" json:"deposits"` + // votes defines all the votes present at genesis. + Votes Votes `protobuf:"bytes,3,rep,name=votes,proto3,castrepeated=Votes" json:"votes"` + // proposals defines all the proposals present at genesis. + Proposals types.Proposals `protobuf:"bytes,4,rep,name=proposals,proto3,castrepeated=Proposals" json:"proposals"` + // params defines all the paramaters of related to deposit. + DepositParams types.DepositParams `protobuf:"bytes,5,opt,name=deposit_params,json=depositParams,proto3" json:"deposit_params" yaml:"deposit_params"` + // params defines all the paramaters of related to voting. + VotingParams types.VotingParams `protobuf:"bytes,6,opt,name=voting_params,json=votingParams,proto3" json:"voting_params" yaml:"voting_params"` + // params defines all the paramaters of related to tally. + TallyParams types.TallyParams `protobuf:"bytes,7,opt,name=tally_params,json=tallyParams,proto3" json:"tally_params" yaml:"tally_params"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} + +func (m *GenesisState) GetStartingProposalId() uint64 { + if m != nil { + return m.StartingProposalId + } + return 0 +} + +func (m *GenesisState) GetDeposits() types.Deposits { + if m != nil { + return m.Deposits + } + return nil +} + +func (m *GenesisState) GetVotes() Votes { + if m != nil { + return m.Votes + } + return nil +} + +func (m *GenesisState) GetProposals() types.Proposals { + if m != nil { + return m.Proposals + } + return nil +} + +func (m *GenesisState) GetDepositParams() types.DepositParams { + if m != nil { + return m.DepositParams + } + return types.DepositParams{} +} + +func (m *GenesisState) GetVotingParams() types.VotingParams { + if m != nil { + return m.VotingParams + } + return types.VotingParams{} +} + +func (m *GenesisState) GetTallyParams() types.TallyParams { + if m != nil { + return m.TallyParams + } + return types.TallyParams{} +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.TallyParams.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size, err := m.VotingParams.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size, err := m.DepositParams.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.Proposals) > 0 { + for iNdEx := len(m.Proposals) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Proposals[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Votes) > 0 { + for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Deposits) > 0 { + for iNdEx := len(m.Deposits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Deposits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.StartingProposalId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.StartingProposalId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.StartingProposalId != 0 { + n += 1 + sovGenesis(uint64(m.StartingProposalId)) + } + if len(m.Deposits) > 0 { + for _, e := range m.Deposits { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Votes) > 0 { + for _, e := range m.Votes { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Proposals) > 0 { + for _, e := range m.Proposals { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = m.DepositParams.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.VotingParams.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.TallyParams.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartingProposalId", wireType) + } + m.StartingProposalId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartingProposalId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deposits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Deposits = append(m.Deposits, types.Deposit{}) + if err := m.Deposits[len(m.Deposits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Votes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Votes = append(m.Votes, Vote{}) + if err := m.Votes[len(m.Votes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proposals", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proposals = append(m.Proposals, types.Proposal{}) + if err := m.Proposals[len(m.Proposals)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.DepositParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VotingParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.VotingParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TallyParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TallyParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/gov/legacy/v040/gov.pb.go b/x/gov/legacy/v040/gov.pb.go index 9e2bb2d0f8fe..34ca3d82a0f9 100644 --- a/x/gov/legacy/v040/gov.pb.go +++ b/x/gov/legacy/v040/gov.pb.go @@ -1,4 +1,4 @@ -// Package v040 is take from: +// Package v040 is taken from: // https://github.com/cosmos/cosmos-sdk/blob/v0.41.1/x/gov/types/gov.pb.go // by copy-pasted only the relevants parts for Vote. package v040 diff --git a/x/gov/legacy/v043/json.go b/x/gov/legacy/v043/json.go new file mode 100644 index 000000000000..db6e47757724 --- /dev/null +++ b/x/gov/legacy/v043/json.go @@ -0,0 +1,32 @@ +package v043 + +import ( + v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040" + "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +// migrateWeightedVotes migrates the ADR-037 weighted votes. +func migrateJSONWeightedVotes(oldVotes v040gov.Votes) types.Votes { + newVotes := make(types.Votes, len(oldVotes)) + for i, oldVote := range oldVotes { + newVotes[i] = migrateVote(oldVote) + } + + return newVotes +} + +// MigrateJSON accepts exported v0.40 x/gov genesis state and migrates it to +// v0.43 x/gov genesis state. The migration includes: +// +// - Gov weighted votes. +func MigrateJSON(oldState *v040gov.GenesisState) *types.GenesisState { + return &types.GenesisState{ + StartingProposalId: oldState.StartingProposalId, + Deposits: oldState.Deposits, + Votes: migrateJSONWeightedVotes(oldState.Votes), + Proposals: oldState.Proposals, + DepositParams: oldState.DepositParams, + VotingParams: oldState.VotingParams, + TallyParams: oldState.TallyParams, + } +} diff --git a/x/gov/legacy/v043/json_test.go b/x/gov/legacy/v043/json_test.go new file mode 100644 index 000000000000..66082e5daf6b --- /dev/null +++ b/x/gov/legacy/v043/json_test.go @@ -0,0 +1,124 @@ +package v043_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040" + v043gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v043" + "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +func TestMigrateJSON(t *testing.T) { + encodingConfig := simapp.MakeTestEncodingConfig() + clientCtx := client.Context{}. + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithJSONMarshaler(encodingConfig.Marshaler) + + voter, err := sdk.AccAddressFromBech32("cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh") + require.NoError(t, err) + govGenState := &v040gov.GenesisState{ + Votes: v040gov.Votes{ + v040gov.NewVote(1, voter, types.OptionAbstain), + v040gov.NewVote(2, voter, types.OptionEmpty), + v040gov.NewVote(3, voter, types.OptionNo), + v040gov.NewVote(4, voter, types.OptionNoWithVeto), + v040gov.NewVote(5, voter, types.OptionYes), + }, + } + + migrated := v043gov.MigrateJSON(govGenState) + + bz, err := clientCtx.JSONMarshaler.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: + // - Votes are all ADR-037 weighted votes with weight 1. + expected := `{ + "deposit_params": { + "max_deposit_period": "0s", + "min_deposit": [] + }, + "deposits": [], + "proposals": [], + "starting_proposal_id": "0", + "tally_params": { + "quorum": "0", + "threshold": "0", + "veto_threshold": "0" + }, + "votes": [ + { + "options": [ + { + "option": "VOTE_OPTION_ABSTAIN", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "1", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "options": [ + { + "option": "VOTE_OPTION_UNSPECIFIED", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "2", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "options": [ + { + "option": "VOTE_OPTION_NO", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "3", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "options": [ + { + "option": "VOTE_OPTION_NO_WITH_VETO", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "4", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "5", + "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + } + ], + "voting_params": { + "voting_period": "0s" + } +}` + + fmt.Println(string(indentedBz)) + + require.Equal(t, expected, string(indentedBz)) +} diff --git a/x/gov/legacy/v043/keys.go b/x/gov/legacy/v043/keys.go new file mode 100644 index 000000000000..8a2528ce5cdf --- /dev/null +++ b/x/gov/legacy/v043/keys.go @@ -0,0 +1,6 @@ +package v043 + +const ( + // ModuleName is the name of the module + ModuleName = "gov" +) diff --git a/x/gov/legacy/v043/store.go b/x/gov/legacy/v043/store.go index 9189e12f736a..0cacf51c3bac 100644 --- a/x/gov/legacy/v043/store.go +++ b/x/gov/legacy/v043/store.go @@ -32,8 +32,17 @@ func migratePrefixProposalAddress(store sdk.KVStore, prefixBz []byte) { } } -// migrateWeightedVotes migrates the ADR-037 weighted votes. -func migrateWeightedVotes(store sdk.KVStore, cdc codec.BinaryMarshaler) error { +// migrateStoreWeightedVotes migrates a legacy vote to an ADR-037 weighted vote. +func migrateVote(oldVote v040gov.Vote) types.Vote { + return types.Vote{ + ProposalId: oldVote.ProposalId, + Voter: oldVote.Voter, + Options: []types.WeightedVoteOption{{Option: oldVote.Option, Weight: sdk.NewDec(1)}}, + } +} + +// migrateStoreWeightedVotes migrates in-place all legacy votes to ADR-037 weighted votes. +func migrateStoreWeightedVotes(store sdk.KVStore, cdc codec.BinaryMarshaler) error { iterator := sdk.KVStorePrefixIterator(store, v040gov.VotesKeyPrefix) defer iterator.Close() @@ -44,12 +53,8 @@ func migrateWeightedVotes(store sdk.KVStore, cdc codec.BinaryMarshaler) error { return err } - newVote := &types.Vote{ - ProposalId: oldVote.ProposalId, - Voter: oldVote.Voter, - Options: []types.WeightedVoteOption{{Option: oldVote.Option, Weight: sdk.NewDec(1)}}, - } - bz, err := cdc.MarshalBinaryBare(newVote) + newVote := migrateVote(oldVote) + bz, err := cdc.MarshalBinaryBare(&newVote) if err != nil { return err } @@ -68,5 +73,5 @@ func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryMarsha store := ctx.KVStore(storeKey) migratePrefixProposalAddress(store, v040gov.DepositsKeyPrefix) migratePrefixProposalAddress(store, v040gov.VotesKeyPrefix) - return migrateWeightedVotes(store, cdc) + return migrateStoreWeightedVotes(store, cdc) } diff --git a/x/gov/legacy/v043/store_test.go b/x/gov/legacy/v043/store_test.go index c9b6ce93aa60..d84e8859109e 100644 --- a/x/gov/legacy/v043/store_test.go +++ b/x/gov/legacy/v043/store_test.go @@ -16,7 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov/types" ) -func TestStoreMigration(t *testing.T) { +func TestMigrateStore(t *testing.T) { cdc := simapp.MakeTestEncodingConfig().Marshaler govKey := sdk.NewKVStoreKey("gov") ctx := testutil.DefaultContext(govKey, sdk.NewTransientStoreKey("transient_test"))