Skip to content

Commit

Permalink
refactor: move gov types to v1beta2 (#10852)
Browse files Browse the repository at this point in the history
## Description

Closes: #10793 



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
  • Loading branch information
atheeshp authored Jan 4, 2022
1 parent 344be86 commit bdee333
Show file tree
Hide file tree
Showing 30 changed files with 329 additions and 322 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#10692](https://github.com/cosmos/cosmos-sdk/pull/10612) `SignerData` takes 2 new fields, `Address` and `PubKey`, which need to get populated when using SIGN_MODE_DIRECT_AUX.
* [\#10748](https://github.com/cosmos/cosmos-sdk/pull/10748) Move legacy `x/gov` api to `v1beta1` directory.
* [\#10816](https://github.com/cosmos/cosmos-sdk/pull/10816) Reuse blocked addresses from the bank module. No need to pass them to distribution.
* [\#10852](https://github.com/cosmos/cosmos-sdk/pull/10852) Move `x/gov/types` to `x/gov/types/v1beta2`.

### Client Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion proto/cosmos/gov/v1beta2/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package cosmos.gov.v1beta2;

import "cosmos/gov/v1beta2/gov.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types";
option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2";

// GenesisState defines the gov module's genesis state.
message GenesisState {
Expand Down
2 changes: 1 addition & 1 deletion proto/cosmos/gov/v1beta2/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types";
option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2";

// VoteOption enumerates the valid vote options for a given governance proposal.
enum VoteOption {
Expand Down
2 changes: 1 addition & 1 deletion proto/cosmos/gov/v1beta2/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "google/api/annotations.proto";
import "cosmos/gov/v1beta2/gov.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types";
option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2";

// Query defines the gRPC querier service for gov module
service Query {
Expand Down
2 changes: 1 addition & 1 deletion proto/cosmos/gov/v1beta2/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types";
option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2";

// Msg defines the gov Msg service.
service Msg {
Expand Down
4 changes: 2 additions & 2 deletions x/authz/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
)

// genGrant returns a slice of authorization grants.
Expand All @@ -31,7 +31,7 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account) []authz.GrantAuthorizat
func generateRandomGrant(r *rand.Rand) *codectypes.Any {
authorizations := make([]*codectypes.Any, 2)
authorizations[0] = newAnyAuthorization(banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))))
authorizations[1] = newAnyAuthorization(authz.NewGenericAuthorization(sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{})))
authorizations[1] = newAnyAuthorization(authz.NewGenericAuthorization(sdk.MsgTypeURL(&v1beta2.MsgSubmitProposal{})))

return authorizations[r.Intn(len(authorizations))]
}
Expand Down
8 changes: 4 additions & 4 deletions x/gov/client/testutil/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
Expand All @@ -17,9 +17,9 @@ func TestIntegrationTestSuite(t *testing.T) {
cfg.NumValidators = 1
suite.Run(t, NewIntegrationTestSuite(cfg))

dp := types.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinDepositTokens)), time.Duration(15)*time.Second)
vp := types.NewVotingParams(time.Duration(5) * time.Second)
genesisState := types.DefaultGenesisState()
dp := v1beta2.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, v1beta2.DefaultMinDepositTokens)), time.Duration(15)*time.Second)
vp := v1beta2.NewVotingParams(time.Duration(5) * time.Second)
genesisState := v1beta2.DefaultGenesisState()
genesisState.DepositParams = &dp
genesisState.VotingParams = &vp
bz, err := cfg.Codec.MarshalJSON(genesisState)
Expand Down
14 changes: 7 additions & 7 deletions x/gov/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,42 @@ package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"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"
)

// GetDepositParams returns the current DepositParams from the global param store
func (keeper Keeper) GetDepositParams(ctx sdk.Context) v1beta1.DepositParams {
var depositParams v1beta1.DepositParams
keeper.paramSpace.Get(ctx, types.ParamStoreKeyDepositParams, &depositParams)
keeper.paramSpace.Get(ctx, v1beta2.ParamStoreKeyDepositParams, &depositParams)
return depositParams
}

// GetVotingParams returns the current VotingParams from the global param store
func (keeper Keeper) GetVotingParams(ctx sdk.Context) v1beta1.VotingParams {
var votingParams v1beta1.VotingParams
keeper.paramSpace.Get(ctx, types.ParamStoreKeyVotingParams, &votingParams)
keeper.paramSpace.Get(ctx, v1beta2.ParamStoreKeyVotingParams, &votingParams)
return votingParams
}

// GetTallyParams returns the current TallyParam from the global param store
func (keeper Keeper) GetTallyParams(ctx sdk.Context) v1beta1.TallyParams {
var tallyParams v1beta1.TallyParams
keeper.paramSpace.Get(ctx, types.ParamStoreKeyTallyParams, &tallyParams)
keeper.paramSpace.Get(ctx, v1beta2.ParamStoreKeyTallyParams, &tallyParams)
return tallyParams
}

// SetDepositParams sets DepositParams to the global param store
func (keeper Keeper) SetDepositParams(ctx sdk.Context, depositParams v1beta1.DepositParams) {
keeper.paramSpace.Set(ctx, types.ParamStoreKeyDepositParams, &depositParams)
keeper.paramSpace.Set(ctx, v1beta2.ParamStoreKeyDepositParams, &depositParams)
}

// SetVotingParams sets VotingParams to the global param store
func (keeper Keeper) SetVotingParams(ctx sdk.Context, votingParams v1beta1.VotingParams) {
keeper.paramSpace.Set(ctx, types.ParamStoreKeyVotingParams, &votingParams)
keeper.paramSpace.Set(ctx, v1beta2.ParamStoreKeyVotingParams, &votingParams)
}

// SetTallyParams sets TallyParams to the global param store
func (keeper Keeper) SetTallyParams(ctx sdk.Context, tallyParams v1beta1.TallyParams) {
keeper.paramSpace.Set(ctx, types.ParamStoreKeyTallyParams, &tallyParams)
keeper.paramSpace.Set(ctx, v1beta2.ParamStoreKeyTallyParams, &tallyParams)
}
33 changes: 17 additions & 16 deletions x/gov/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,35 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"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"
)

// NewQuerier creates a new gov Querier instance
func NewQuerier(keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
switch path[0] {
case types.QueryParams:
case v1beta2.QueryParams:
return queryParams(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryProposals:
case v1beta2.QueryProposals:
return queryProposals(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryProposal:
case v1beta2.QueryProposal:
return queryProposal(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryDeposits:
case v1beta2.QueryDeposits:
return queryDeposits(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryDeposit:
case v1beta2.QueryDeposit:
return queryDeposit(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryVotes:
case v1beta2.QueryVotes:
return queryVotes(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryVote:
case v1beta2.QueryVote:
return queryVote(ctx, path[1:], req, keeper, legacyQuerierCdc)

case types.QueryTally:
case v1beta2.QueryTally:
return queryTally(ctx, path[1:], req, keeper, legacyQuerierCdc)

default:
Expand All @@ -47,21 +48,21 @@ func NewQuerier(keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier

func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
switch path[0] {
case types.ParamDeposit:
case v1beta2.ParamDeposit:
bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, keeper.GetDepositParams(ctx))
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil

case types.ParamVoting:
case v1beta2.ParamVoting:
bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, keeper.GetVotingParams(ctx))
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil

case types.ParamTallying:
case v1beta2.ParamTallying:
bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, keeper.GetTallyParams(ctx))
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
Expand All @@ -75,7 +76,7 @@ func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper K

// nolint: unparam
func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var params types.QueryProposalParams
var params v1beta2.QueryProposalParams
err := legacyQuerierCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand All @@ -96,7 +97,7 @@ func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper

// nolint: unparam
func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var params types.QueryDepositParams
var params v1beta2.QueryDepositParams
err := legacyQuerierCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand All @@ -113,7 +114,7 @@ func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper

// nolint: unparam
func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var params types.QueryVoteParams
var params v1beta2.QueryVoteParams
err := legacyQuerierCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand All @@ -130,7 +131,7 @@ func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Kee

// nolint: unparam
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var params types.QueryProposalParams
var params v1beta2.QueryProposalParams
err := legacyQuerierCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand All @@ -151,7 +152,7 @@ func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper

// nolint: unparam
func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var params types.QueryProposalParams
var params v1beta2.QueryProposalParams
err := legacyQuerierCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand Down
5 changes: 3 additions & 2 deletions x/gov/keeper/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov/keeper"
"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"
)

const custom = "custom"
Expand Down Expand Up @@ -202,7 +203,7 @@ func TestQueries(t *testing.T) {

proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit4.Amount...)
proposal2.Status = v1beta1.StatusVotingPeriod
proposal2.VotingEndTime = proposal2.VotingEndTime.Add(types.DefaultPeriod)
proposal2.VotingEndTime = proposal2.VotingEndTime.Add(v1beta2.DefaultPeriod)

deposit5 := v1beta1.NewDeposit(proposal3.ProposalId, TestAddrs[1], depositParams.MinDeposit)
depositer5, err := sdk.AccAddressFromBech32(deposit5.Depositor)
Expand All @@ -212,7 +213,7 @@ func TestQueries(t *testing.T) {

proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit5.Amount...)
proposal3.Status = v1beta1.StatusVotingPeriod
proposal3.VotingEndTime = proposal3.VotingEndTime.Add(types.DefaultPeriod)
proposal3.VotingEndTime = proposal3.VotingEndTime.Add(v1beta2.DefaultPeriod)
// total deposit of TestAddrs[1] on proposal #3 is worth the proposal deposit + individual deposit
deposit5.Amount = deposit5.Amount.Add(deposit3.Amount...)

Expand Down
12 changes: 6 additions & 6 deletions x/gov/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
)

// Simulation parameter constants
Expand Down Expand Up @@ -94,17 +94,17 @@ func RandomizedGenState(simState *module.SimulationState) {
func(r *rand.Rand) { veto = GenTallyParamsVeto(r) },
)

govGenesis := types.NewGenesisState(
govGenesis := v1beta2.NewGenesisState(
startingProposalID,
types.NewDepositParams(minDeposit, depositPeriod),
types.NewVotingParams(votingPeriod),
types.NewTallyParams(quorum, threshold, veto),
v1beta2.NewDepositParams(minDeposit, depositPeriod),
v1beta2.NewVotingParams(votingPeriod),
v1beta2.NewTallyParams(quorum, threshold, veto),
)

bz, err := json.MarshalIndent(&govGenesis, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated governance parameters:\n%s\n", bz)
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(govGenesis)
simState.GenState[v1beta2.ModuleName] = simState.Cdc.MustMarshalJSON(govGenesis)
}
12 changes: 6 additions & 6 deletions x/gov/simulation/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/gov/simulation"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
)

// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState.
Expand All @@ -37,8 +37,8 @@ func TestRandomizedGenState(t *testing.T) {

simulation.RandomizedGenState(&simState)

var govGenesis types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &govGenesis)
var govGenesis v1beta2.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[v1beta2.ModuleName], &govGenesis)

dec1, _ := sdk.NewDecFromStr("0.361000000000000000")
dec2, _ := sdk.NewDecFromStr("0.512000000000000000")
Expand All @@ -51,9 +51,9 @@ func TestRandomizedGenState(t *testing.T) {
require.Equal(t, dec2.String(), govGenesis.TallyParams.Threshold)
require.Equal(t, dec3.String(), govGenesis.TallyParams.VetoThreshold)
require.Equal(t, uint64(0x28), govGenesis.StartingProposalId)
require.Equal(t, []*types.Deposit{}, govGenesis.Deposits)
require.Equal(t, []*types.Vote{}, govGenesis.Votes)
require.Equal(t, []*types.Proposal{}, govGenesis.Proposals)
require.Equal(t, []*v1beta2.Deposit{}, govGenesis.Deposits)
require.Equal(t, []*v1beta2.Vote{}, govGenesis.Votes)
require.Equal(t, []*v1beta2.Proposal{}, govGenesis.Proposals)
}

// TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState.
Expand Down
2 changes: 1 addition & 1 deletion x/gov/types/codec.go → x/gov/types/v1beta2/codec.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package types
package v1beta2

import (
"github.com/cosmos/cosmos-sdk/codec"
Expand Down
27 changes: 27 additions & 0 deletions x/gov/types/v1beta2/content.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package v1beta2

import sdk "github.com/cosmos/cosmos-sdk/types"

// Copied over from /x/gov/types/keys.go to avoid circular imports
const (
ModuleName = "gov"

RouterKey = ModuleName
)

// Content defines an interface that a proposal must implement. It contains
// information such as the title and description along with the type and routing
// information for the appropriate handler to process the proposal. Content can
// have additional fields, which will handled by a proposal's Handler.
type Content interface {
GetTitle() string
GetDescription() string
ProposalRoute() string
ProposalType() string
ValidateBasic() error
String() string
}

// Handler defines a function that handles a proposal after it has passed the
// governance process.
type Handler func(ctx sdk.Context, content Content) error
2 changes: 1 addition & 1 deletion x/gov/types/deposit.go → x/gov/types/v1beta2/deposit.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package types
package v1beta2

import (
"fmt"
Expand Down
2 changes: 1 addition & 1 deletion x/gov/types/genesis.go → x/gov/types/v1beta2/genesis.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package types
package v1beta2

import (
"errors"
Expand Down
Loading

0 comments on commit bdee333

Please sign in to comment.