feat(cli): cancel gov proposal by proposer before voting period ends (#13010)
Co-authored-by: Anil Kumar Kammari <anil@vitwit.com> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Amaury <1293565+amaurym@users.noreply.github.com> Co-authored-by: Robert Zaremba <robert@zaremba.ch> Co-authored-by: Marko <marbar3778@yahoo.com> Closes https://github.com/cosmos/cosmos-sdk/issues/11554
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
qtypes "github.com/cosmos/cosmos-sdk/types/query"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/gov"
|
||||
)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ func (s *E2ETestSuite) TestGetProposalsGRPC() {
|
||||
"valid request",
|
||||
fmt.Sprintf("%s/cosmos/gov/v1/proposals", val.APIAddress),
|
||||
map[string]string{},
|
||||
3,
|
||||
4,
|
||||
false,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ func (s *E2ETestSuite) TestCmdParams() {
|
||||
{
|
||||
"json output",
|
||||
[]string{fmt.Sprintf("--%s=json", flags.FlagOutput)},
|
||||
`{"voting_params":{"voting_period":"172800s"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s","voting_period":"172800s","quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","min_initial_deposit_ratio":"0.000000000000000000"}}`,
|
||||
`{"voting_params":{"voting_period":"172800s"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s","voting_period":"172800s","quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","min_initial_deposit_ratio":"0.000000000000000000","proposal_cancel_ratio":"0.500000000000000000","proposal_cancel_dest":""}}`,
|
||||
},
|
||||
{
|
||||
"text output",
|
||||
@@ -40,6 +40,8 @@ params:
|
||||
- amount: "10000000"
|
||||
denom: stake
|
||||
min_initial_deposit_ratio: "0.000000000000000000"
|
||||
proposal_cancel_dest: ""
|
||||
proposal_cancel_ratio: "0.500000000000000000"
|
||||
quorum: "0.334000000000000000"
|
||||
threshold: "0.500000000000000000"
|
||||
veto_threshold: "0.334000000000000000"
|
||||
@@ -306,7 +308,7 @@ func (s *E2ETestSuite) TestCmdGetProposals() {
|
||||
var proposals v1.QueryProposalsResponse
|
||||
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposals), out.String())
|
||||
s.Require().Len(proposals.Proposals, 3)
|
||||
s.Require().Greater(len(proposals.Proposals), 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+138
-10
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
||||
govclitestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
@@ -41,36 +42,51 @@ func (s *E2ETestSuite) SetupSuite() {
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
val := s.network.Validators[0]
|
||||
clientCtx := val.ClientCtx
|
||||
var resp sdk.TxResponse
|
||||
|
||||
// create a proposal with deposit
|
||||
_, err = govclitestutil.MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
out, err := govclitestutil.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, v1.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
|
||||
|
||||
// vote for proposal
|
||||
_, err = govclitestutil.MsgVote(val.ClientCtx, val.Address.String(), "1", "yes")
|
||||
out, err = govclitestutil.MsgVote(val.ClientCtx, val.Address.String(), "1", "yes")
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
|
||||
|
||||
// create a proposal without deposit
|
||||
_, err = govclitestutil.MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
out, err = govclitestutil.MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
"Text Proposal 2", "Where is the title!?", v1beta1.ProposalTypeText)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
|
||||
|
||||
// create a proposal3 with deposit
|
||||
_, err = govclitestutil.MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
out, err = govclitestutil.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, v1.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
|
||||
|
||||
// create a proposal4 with deposit to check the cancel proposal cli tx
|
||||
out, err = govclitestutil.MsgSubmitLegacyProposal(val.ClientCtx, val.Address.String(),
|
||||
"Text Proposal 4", "Where is the title!?", v1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
|
||||
|
||||
// vote for proposal3 as val
|
||||
_, err = govclitestutil.MsgVote(val.ClientCtx, val.Address.String(), "3", "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05")
|
||||
out, err = govclitestutil.MsgVote(val.ClientCtx, val.Address.String(), "3", "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05")
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TearDownSuite() {
|
||||
@@ -260,6 +276,118 @@ func (s *E2ETestSuite) TestNewCmdSubmitLegacyProposal() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestNewCmdCancelProposal() {
|
||||
val := s.network.Validators[0]
|
||||
val2 := sdk.AccAddress("invalid_acc_addr")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectErr bool
|
||||
expectedCode uint32
|
||||
}{
|
||||
{
|
||||
"without proposal id",
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
true, 0,
|
||||
},
|
||||
{
|
||||
"invalid proposal id",
|
||||
[]string{
|
||||
"asdasd",
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
true, 0,
|
||||
},
|
||||
{
|
||||
"valid proposal-id but invalid proposer",
|
||||
[]string{
|
||||
"4",
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val2),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
true, 0,
|
||||
},
|
||||
{
|
||||
"valid proposer",
|
||||
[]string{
|
||||
"4",
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
false, 0,
|
||||
},
|
||||
{
|
||||
"proposal not exists after cancel",
|
||||
[]string{
|
||||
"4",
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
|
||||
},
|
||||
false, 17,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
var resp sdk.TxResponse
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdCancelProposal()
|
||||
clientCtx := val.ClientCtx
|
||||
var balRes banktypes.QueryAllBalancesResponse
|
||||
var newBalance banktypes.QueryAllBalancesResponse
|
||||
if !tc.expectErr && tc.expectedCode == 0 {
|
||||
resp, err := clitestutil.QueryBalancesExec(clientCtx, val.Address)
|
||||
s.Require().NoError(err)
|
||||
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
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(), &resp), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, tc.expectedCode))
|
||||
|
||||
if !tc.expectErr && tc.expectedCode == 0 {
|
||||
resp, err := clitestutil.QueryBalancesExec(clientCtx, val.Address)
|
||||
s.Require().NoError(err)
|
||||
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &newBalance)
|
||||
s.Require().NoError(err)
|
||||
remainingAmount := v1.DefaultMinDepositTokens.Mul(
|
||||
v1.DefaultProposalCancelRatio.Mul(sdk.MustNewDecFromStr("100")).TruncateInt(),
|
||||
).Quo(sdk.NewIntFromUint64(100))
|
||||
|
||||
// new balance = old balance + remaining amount from proposal deposit - txFee (cancel proposal)
|
||||
txFee := sdk.NewInt(10)
|
||||
s.Require().True(
|
||||
newBalance.Balances.AmountOf(s.network.Config.BondDenom).Equal(
|
||||
balRes.Balances.AmountOf(s.network.Config.BondDenom).Add(remainingAmount).Sub(txFee),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestNewCmdDeposit() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
_ "github.com/cosmos/cosmos-sdk/x/consensus"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
|
||||
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
@@ -106,7 +106,7 @@ func TestImportExportQueues(t *testing.T) {
|
||||
genesisState[banktypes.ModuleName] = s1.cdc.MustMarshalJSON(bankGenState)
|
||||
genesisState[types.ModuleName] = s1.cdc.MustMarshalJSON(govGenState)
|
||||
genesisState[stakingtypes.ModuleName] = s1.cdc.MustMarshalJSON(stakingGenState)
|
||||
genesisState[distributiontypes.ModuleName] = s1.cdc.MustMarshalJSON(distributionGenState)
|
||||
genesisState[disttypes.ModuleName] = s1.cdc.MustMarshalJSON(distributionGenState)
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/mint"
|
||||
)
|
||||
@@ -23,6 +24,7 @@ func TestItCreatesModuleAccountOnInitBlock(t *testing.T) {
|
||||
configurator.StakingModule(),
|
||||
configurator.BankModule(),
|
||||
configurator.GovModule(),
|
||||
configurator.DistributionModule(),
|
||||
configurator.ConsensusModule(),
|
||||
),
|
||||
&accountKeeper,
|
||||
|
||||
Reference in New Issue
Block a user