feat: Add CLI for new gov proposal (#11013)
* feat: Add CLI for new proposal * Add changelog * Add comment * Add metadata * Add tests for parsing * Add CLI test * Use legacy submit proposal in other modules * Update x/gov/client/cli/tx.go * Update x/gov/client/cli/tx.go * Update x/gov/client/cli/tx.go * Remove deprecated cobra field * Update x/gov/client/cli/tx.go Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com>
This commit is contained in:
parent
24c97d529f
commit
62d97907e2
|
@ -124,6 +124,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||
|
||||
* [\#9594](https://github.com/cosmos/cosmos-sdk/pull/9594) Remove legacy REST API. Please see the [REST Endpoints Migration guide](https://docs.cosmos.network/master/migrations/rest.html) to migrate to the new REST endpoints.
|
||||
* [\#9995](https://github.com/cosmos/cosmos-sdk/pull/9995) Increased gas cost for creating proposals.
|
||||
* [\#11013](https://github.com/cosmos/cosmos-sdk/pull/) The `tx gov submit-proposal` command has changed syntax to support the new Msg-based gov proposals. To access the old CLI command, please use `tx gov submit-legacy-proposal`.
|
||||
|
||||
### CLI Breaking Changes
|
||||
|
||||
|
|
|
@ -1503,7 +1503,7 @@ func (s *IntegrationTestSuite) TestAuxSigner() {
|
|||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
s.Run(tc.name, func() {
|
||||
_, err := govtestutil.MsgSubmitProposal(
|
||||
_, err := govtestutil.MsgSubmitLegacyProposal(
|
||||
val.ClientCtx,
|
||||
val.Address.String(),
|
||||
"test",
|
||||
|
@ -1747,7 +1747,7 @@ func (s *IntegrationTestSuite) TestAuxToFee() {
|
|||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
s.Run(tc.name, func() {
|
||||
res, err := govtestutil.MsgSubmitProposal(
|
||||
res, err := govtestutil.MsgSubmitLegacyProposal(
|
||||
val.ClientCtx,
|
||||
tipper.String(),
|
||||
"test",
|
||||
|
|
|
@ -54,7 +54,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
s.Require().NoError(err)
|
||||
|
||||
// create a proposal with deposit
|
||||
_, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(),
|
||||
_, err = govtestutil.MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
"Text Proposal 1", "Where is the title!?", govv1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govv1beta2.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
|
|
|
@ -752,7 +752,7 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() {
|
|||
|
||||
// granted fee allowance for an account which is not in state and creating
|
||||
// any tx with it by using --fee-account shouldn't fail
|
||||
out, err := govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(),
|
||||
out, err := govtestutil.MsgSubmitLegacyProposal(val.ClientCtx, grantee.String(),
|
||||
"Text Proposal", "No desc", govv1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFeeGranter, granter.String()),
|
||||
)
|
||||
|
@ -892,7 +892,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() {
|
|||
{
|
||||
"valid proposal tx",
|
||||
func() (testutil.BufferWriter, error) {
|
||||
return govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(),
|
||||
return govtestutil.MsgSubmitLegacyProposal(val.ClientCtx, grantee.String(),
|
||||
"Text Proposal", "No desc", govv1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFeeGranter, granter.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(100))).String()),
|
||||
|
|
|
@ -7,11 +7,20 @@ import (
|
|||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
govutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
|
||||
)
|
||||
|
||||
func parseSubmitProposalFlags(fs *pflag.FlagSet) (*proposal, error) {
|
||||
proposal := &proposal{}
|
||||
type legacyProposal struct {
|
||||
Title string
|
||||
Description string
|
||||
Type string
|
||||
Deposit string
|
||||
}
|
||||
|
||||
func parseSubmitLegacyProposalFlags(fs *pflag.FlagSet) (*legacyProposal, error) {
|
||||
proposal := &legacyProposal{}
|
||||
proposalFile, _ := fs.GetString(FlagProposal)
|
||||
|
||||
if proposalFile == "" {
|
||||
|
@ -42,3 +51,43 @@ func parseSubmitProposalFlags(fs *pflag.FlagSet) (*proposal, error) {
|
|||
|
||||
return proposal, nil
|
||||
}
|
||||
|
||||
// proposal defines the new Msg-based proposal.
|
||||
type proposal struct {
|
||||
// Msgs defines an array of sdk.Msgs proto-JSON-encoded as Anys.
|
||||
Messages []json.RawMessage
|
||||
Metadata []byte
|
||||
Deposit string
|
||||
}
|
||||
|
||||
func parseSubmitProposal(cdc codec.Codec, path string) ([]sdk.Msg, []byte, sdk.Coins, error) {
|
||||
var proposal proposal
|
||||
|
||||
contents, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(contents, &proposal)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
msgs := make([]sdk.Msg, len(proposal.Messages))
|
||||
for i, anyJSON := range proposal.Messages {
|
||||
var msg sdk.Msg
|
||||
err := cdc.UnmarshalInterfaceJSON(anyJSON, &msg)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
msgs[i] = msg
|
||||
}
|
||||
|
||||
deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return msgs, proposal.Metadata, deposit, nil
|
||||
}
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
||||
func TestParseSubmitProposalFlags(t *testing.T) {
|
||||
func TestParseSubmitLegacyProposalFlags(t *testing.T) {
|
||||
okJSON := testutil.WriteToNewTempFile(t, `
|
||||
{
|
||||
"title": "Test Proposal",
|
||||
|
@ -19,21 +29,21 @@ func TestParseSubmitProposalFlags(t *testing.T) {
|
|||
`)
|
||||
|
||||
badJSON := testutil.WriteToNewTempFile(t, "bad json")
|
||||
fs := NewCmdSubmitProposal().Flags()
|
||||
fs := NewCmdSubmitLegacyProposal().Flags()
|
||||
|
||||
// nonexistent json
|
||||
fs.Set(FlagProposal, "fileDoesNotExist")
|
||||
_, err := parseSubmitProposalFlags(fs)
|
||||
_, err := parseSubmitLegacyProposalFlags(fs)
|
||||
require.Error(t, err)
|
||||
|
||||
// invalid json
|
||||
fs.Set(FlagProposal, badJSON.Name())
|
||||
_, err = parseSubmitProposalFlags(fs)
|
||||
_, err = parseSubmitLegacyProposalFlags(fs)
|
||||
require.Error(t, err)
|
||||
|
||||
// ok json
|
||||
fs.Set(FlagProposal, okJSON.Name())
|
||||
proposal1, err := parseSubmitProposalFlags(fs)
|
||||
proposal1, err := parseSubmitLegacyProposalFlags(fs)
|
||||
require.Nil(t, err, "unexpected error")
|
||||
require.Equal(t, "Test Proposal", proposal1.Title)
|
||||
require.Equal(t, "My awesome proposal", proposal1.Description)
|
||||
|
@ -43,7 +53,7 @@ func TestParseSubmitProposalFlags(t *testing.T) {
|
|||
// flags that can't be used with --proposal
|
||||
for _, incompatibleFlag := range ProposalFlags {
|
||||
fs.Set(incompatibleFlag, "some value")
|
||||
_, err := parseSubmitProposalFlags(fs)
|
||||
_, err := parseSubmitLegacyProposalFlags(fs)
|
||||
require.Error(t, err)
|
||||
fs.Set(incompatibleFlag, "")
|
||||
}
|
||||
|
@ -54,7 +64,7 @@ func TestParseSubmitProposalFlags(t *testing.T) {
|
|||
fs.Set(FlagDescription, proposal1.Description)
|
||||
fs.Set(FlagProposalType, proposal1.Type)
|
||||
fs.Set(FlagDeposit, proposal1.Deposit)
|
||||
proposal2, err := parseSubmitProposalFlags(fs)
|
||||
proposal2, err := parseSubmitLegacyProposalFlags(fs)
|
||||
|
||||
require.Nil(t, err, "unexpected error")
|
||||
require.Equal(t, proposal1.Title, proposal2.Title)
|
||||
|
@ -67,3 +77,83 @@ func TestParseSubmitProposalFlags(t *testing.T) {
|
|||
err = badJSON.Close()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
}
|
||||
|
||||
func TestParseSubmitProposal(t *testing.T) {
|
||||
_, _, addr := testdata.KeyTestPubAddr()
|
||||
interfaceRegistry := codectypes.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
banktypes.RegisterInterfaces(interfaceRegistry)
|
||||
stakingtypes.RegisterInterfaces(interfaceRegistry)
|
||||
v1beta1.RegisterInterfaces(interfaceRegistry)
|
||||
v1beta2.RegisterInterfaces(interfaceRegistry)
|
||||
expectedMetadata := []byte{42}
|
||||
|
||||
okJSON := testutil.WriteToNewTempFile(t, fmt.Sprintf(`
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"@type": "/cosmos.bank.v1beta1.MsgSend",
|
||||
"from_address": "%s",
|
||||
"to_address": "%s",
|
||||
"amount":[{"denom": "stake","amount": "10"}]
|
||||
},
|
||||
{
|
||||
"@type": "/cosmos.staking.v1beta1.MsgDelegate",
|
||||
"delegator_address": "%s",
|
||||
"validator_address": "%s",
|
||||
"amount":{"denom": "stake","amount": "10"}
|
||||
},
|
||||
{
|
||||
"@type": "/cosmos.gov.v1beta2.MsgExecLegacyContent",
|
||||
"authority": "%s",
|
||||
"content": {
|
||||
"@type": "/cosmos.gov.v1beta1.TextProposal",
|
||||
"title": "My awesome title",
|
||||
"description": "My awesome description"
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": "%s",
|
||||
"deposit": "1000test"
|
||||
}
|
||||
`, addr, addr, addr, addr, addr, base64.StdEncoding.EncodeToString(expectedMetadata)))
|
||||
|
||||
badJSON := testutil.WriteToNewTempFile(t, "bad json")
|
||||
|
||||
// nonexistent json
|
||||
_, _, _, err := parseSubmitProposal(cdc, "fileDoesNotExist")
|
||||
require.Error(t, err)
|
||||
|
||||
// invalid json
|
||||
_, _, _, err = parseSubmitProposal(cdc, badJSON.Name())
|
||||
require.Error(t, err)
|
||||
|
||||
// ok json
|
||||
msgs, metadata, deposit, err := parseSubmitProposal(cdc, okJSON.Name())
|
||||
require.NoError(t, err, "unexpected error")
|
||||
require.Equal(t, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(1000))), deposit)
|
||||
require.Equal(t, expectedMetadata, metadata)
|
||||
require.Len(t, msgs, 3)
|
||||
msg1, ok := msgs[0].(*banktypes.MsgSend)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, addr.String(), msg1.FromAddress)
|
||||
require.Equal(t, addr.String(), msg1.ToAddress)
|
||||
require.Equal(t, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))), msg1.Amount)
|
||||
msg2, ok := msgs[1].(*stakingtypes.MsgDelegate)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, addr.String(), msg2.DelegatorAddress)
|
||||
require.Equal(t, addr.String(), msg2.ValidatorAddress)
|
||||
require.Equal(t, sdk.NewCoin("stake", sdk.NewInt(10)), msg2.Amount)
|
||||
msg3, ok := msgs[2].(*v1beta2.MsgExecLegacyContent)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, addr.String(), msg3.Authority)
|
||||
textProp, ok := msg3.Content.GetCachedValue().(*v1beta1.TextProposal)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "My awesome title", textProp.Title)
|
||||
require.Equal(t, "My awesome description", textProp.Description)
|
||||
|
||||
err = okJSON.Close()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
err = badJSON.Close()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
}
|
||||
|
|
|
@ -20,23 +20,21 @@ import (
|
|||
|
||||
// Proposal flags
|
||||
const (
|
||||
// Deprecated: only used for v1beta1 legacy proposals.
|
||||
FlagTitle = "title"
|
||||
// Deprecated: only used for v1beta1 legacy proposals.
|
||||
FlagDescription = "description"
|
||||
// Deprecated: only used for v1beta1 legacy proposals.
|
||||
FlagProposalType = "type"
|
||||
// Deprecated: only used for v1beta1 legacy proposals.
|
||||
FlagDeposit = "deposit"
|
||||
flagVoter = "voter"
|
||||
flagDepositor = "depositor"
|
||||
flagStatus = "status"
|
||||
// Deprecated: only used for v1beta1 legacy proposals.
|
||||
FlagProposal = "proposal"
|
||||
)
|
||||
|
||||
type proposal struct {
|
||||
Title string
|
||||
Description string
|
||||
Type string
|
||||
Deposit string
|
||||
}
|
||||
|
||||
// ProposalFlags defines the core required fields of a proposal. It is used to
|
||||
// verify that these values are not provided in conjunction with a JSON proposal
|
||||
// file.
|
||||
|
@ -61,19 +59,18 @@ func NewTxCmd(propCmds []*cobra.Command) *cobra.Command {
|
|||
RunE: client.ValidateCmd,
|
||||
}
|
||||
|
||||
// TODO Add CLI for new submit proposal
|
||||
// https://github.com/cosmos/cosmos-sdk/issues/10952
|
||||
cmdSubmitProp := NewCmdSubmitProposal()
|
||||
cmdSubmitLegacyProp := NewCmdSubmitLegacyProposal()
|
||||
for _, propCmd := range propCmds {
|
||||
flags.AddTxFlagsToCmd(propCmd)
|
||||
cmdSubmitProp.AddCommand(propCmd)
|
||||
cmdSubmitLegacyProp.AddCommand(propCmd)
|
||||
}
|
||||
|
||||
govTxCmd.AddCommand(
|
||||
NewCmdDeposit(),
|
||||
NewCmdVote(),
|
||||
NewCmdWeightedVote(),
|
||||
cmdSubmitProp,
|
||||
NewCmdSubmitProposal(),
|
||||
cmdSubmitLegacyProp,
|
||||
)
|
||||
|
||||
return govTxCmd
|
||||
|
@ -83,13 +80,71 @@ func NewTxCmd(propCmds []*cobra.Command) *cobra.Command {
|
|||
func NewCmdSubmitProposal() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "submit-proposal",
|
||||
Short: "Submit a proposal along with an initial deposit",
|
||||
Short: "Submit a proposal along with some messages and metadata",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Submit a proposal along with an initial deposit.
|
||||
fmt.Sprintf(`Submit a proposal along with some messages and metadata.
|
||||
Messages, metadata and deposit are defined in a JSON file.
|
||||
|
||||
Example:
|
||||
$ %s tx gov submit-proposal path/to/proposal.json
|
||||
|
||||
Where proposal.json contains:
|
||||
|
||||
{
|
||||
// array of proto-JSON-encoded sdk.Msgs
|
||||
"messages": [
|
||||
{
|
||||
"@type": "/cosmos.bank.v1beta1.MsgSend",
|
||||
"from_address": "cosmos1...",
|
||||
"to_address": "cosmos1...",
|
||||
"amount":[{"denom": "stake","amount": "10"}]
|
||||
}
|
||||
],
|
||||
"metadata: "4pIMOgIGx1vZGU=", // base64-encoded metadata
|
||||
"deposit": "10stake"
|
||||
}
|
||||
`,
|
||||
version.AppName,
|
||||
),
|
||||
),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgs, metadata, deposit, err := parseSubmitProposal(clientCtx.Codec, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := v1beta2.NewMsgSubmitProposal(msgs, deposit, clientCtx.GetFromAddress().String(), metadata)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid message: %w", err)
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
}
|
||||
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewCmdSubmitLegacyProposal implements submitting a proposal transaction command.
|
||||
// Deprecated: please use NewCmdSubmitProposal instead.
|
||||
func NewCmdSubmitLegacyProposal() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "submit-legacy-proposal",
|
||||
Short: "Submit a legacy proposal along with an initial deposit",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Submit a legacy proposal along with an initial deposit.
|
||||
Proposal title, description, type and deposit can be given directly or through a proposal JSON file.
|
||||
|
||||
Example:
|
||||
$ %s tx gov submit-proposal --proposal="path/to/proposal.json" --from mykey
|
||||
$ %s tx gov submit-legacy-proposal --proposal="path/to/proposal.json" --from mykey
|
||||
|
||||
Where proposal.json contains:
|
||||
|
||||
|
@ -102,7 +157,7 @@ Where proposal.json contains:
|
|||
|
||||
Which is equivalent to:
|
||||
|
||||
$ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey
|
||||
$ %s tx gov submit-legacy-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey
|
||||
`,
|
||||
version.AppName, version.AppName,
|
||||
),
|
||||
|
@ -113,7 +168,7 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr
|
|||
return err
|
||||
}
|
||||
|
||||
proposal, err := parseSubmitProposalFlags(cmd.Flags())
|
||||
proposal, err := parseSubmitLegacyProposalFlags(cmd.Flags())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse proposal: %w", err)
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func (s *DepositTestSuite) createProposal(val *network.Validator, initialDeposit
|
|||
exactArgs = append(exactArgs, fmt.Sprintf("--%s=%s", cli.FlagDeposit, initialDeposit.String()))
|
||||
}
|
||||
|
||||
_, err := MsgSubmitProposal(
|
||||
_, err := MsgSubmitLegacyProposal(
|
||||
val.ClientCtx,
|
||||
val.Address.String(),
|
||||
fmt.Sprintf("Text Proposal %d", id),
|
||||
|
|
|
@ -31,6 +31,20 @@ func MsgSubmitProposal(clientCtx client.Context, from, title, description, propo
|
|||
return clitestutil.ExecTestCLICmd(clientCtx, govcli.NewCmdSubmitProposal(), args)
|
||||
}
|
||||
|
||||
// MsgSubmitLegacyProposal creates a tx for submit legacy proposal
|
||||
func MsgSubmitLegacyProposal(clientCtx client.Context, from, title, description, proposalType string, extraArgs ...string) (testutil.BufferWriter, error) {
|
||||
args := append([]string{
|
||||
fmt.Sprintf("--%s=%s", govcli.FlagTitle, title),
|
||||
fmt.Sprintf("--%s=%s", govcli.FlagDescription, description),
|
||||
fmt.Sprintf("--%s=%s", govcli.FlagProposalType, proposalType),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, from),
|
||||
}, commonArgs...)
|
||||
|
||||
args = append(args, extraArgs...)
|
||||
|
||||
return clitestutil.ExecTestCLICmd(clientCtx, govcli.NewCmdSubmitLegacyProposal(), args)
|
||||
}
|
||||
|
||||
// MsgVote votes for a proposal
|
||||
func MsgVote(clientCtx client.Context, from, id, vote string, extraArgs ...string) (testutil.BufferWriter, error) {
|
||||
args := append([]string{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package testutil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -15,7 +16,9 @@ import (
|
|||
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
||||
"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"
|
||||
)
|
||||
|
@ -44,7 +47,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
val := s.network.Validators[0]
|
||||
|
||||
// create a proposal with deposit
|
||||
_, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(),
|
||||
_, err = MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
"Text Proposal 1", "Where is the title!?", v1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, v1beta2.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
|
@ -56,14 +59,14 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
s.Require().NoError(err)
|
||||
|
||||
// create a proposal without deposit
|
||||
_, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(),
|
||||
_, err = MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
"Text Proposal 2", "Where is the title!?", v1beta1.ProposalTypeText)
|
||||
s.Require().NoError(err)
|
||||
_, err = s.network.WaitForHeight(1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// create a proposal3 with deposit
|
||||
_, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(),
|
||||
_, err = MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
"Text Proposal 3", "Where is the title!?", v1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, v1beta2.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
|
@ -278,6 +281,88 @@ func (s *IntegrationTestSuite) TestCmdTally() {
|
|||
|
||||
func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
// Create an legacy proposal JSON, make sure it doesn't pass this new CLI
|
||||
// command.
|
||||
invalidProp := `{
|
||||
"title": "",
|
||||
"description": "Where is the title!?",
|
||||
"type": "Text",
|
||||
"deposit": "-324foocoin"
|
||||
}`
|
||||
invalidPropFile := testutil.WriteToNewTempFile(s.T(), invalidProp)
|
||||
|
||||
// Create a valid new proposal JSON.
|
||||
propMetadata := []byte{42}
|
||||
validProp := fmt.Sprintf(`
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"@type": "/cosmos.gov.v1beta2.MsgExecLegacyContent",
|
||||
"authority": "%s",
|
||||
"content": {
|
||||
"@type": "/cosmos.gov.v1beta1.TextProposal",
|
||||
"title": "My awesome title",
|
||||
"description": "My awesome description"
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": "%s",
|
||||
"deposit": "%s"
|
||||
}`, authtypes.NewModuleAddress(types.ModuleName), base64.StdEncoding.EncodeToString(propMetadata), sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)))
|
||||
validPropFile := testutil.WriteToNewTempFile(s.T(), validProp)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectErr bool
|
||||
expectedCode uint32
|
||||
respType proto.Message
|
||||
}{
|
||||
{
|
||||
"invalid proposal",
|
||||
[]string{
|
||||
invalidPropFile.Name(),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
true, 0, nil,
|
||||
},
|
||||
{
|
||||
"valid proposal",
|
||||
[]string{
|
||||
validPropFile.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
false, 0, &sdk.TxResponse{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdSubmitProposal()
|
||||
clientCtx := val.ClientCtx
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
|
||||
txResp := tc.respType.(*sdk.TxResponse)
|
||||
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestNewCmdSubmitLegacyProposal() {
|
||||
val := s.network.Validators[0]
|
||||
invalidProp := `{
|
||||
"title": "",
|
||||
"description": "Where is the title!?",
|
||||
|
@ -352,7 +437,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() {
|
|||
tc := tc
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdSubmitProposal()
|
||||
cmd := cli.NewCmdSubmitLegacyProposal()
|
||||
clientCtx := val.ClientCtx
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
|
|
Loading…
Reference in New Issue