diff --git a/.changelog/unreleased/state-breaking/2913-gov-spam.md b/.changelog/unreleased/state-breaking/2913-gov-spam.md new file mode 100644 index 00000000000..1f80acb0ae1 --- /dev/null +++ b/.changelog/unreleased/state-breaking/2913-gov-spam.md @@ -0,0 +1,3 @@ +- Remove `GovPreventSpamDecorator` and initialize the `MinInitialDepositRatio` gov + param to `10%`. + ([\#2913](https://github.com/cosmos/gaia/pull/2913)) \ No newline at end of file diff --git a/ante/ante.go b/ante/ante.go index 4970c135919..433e434aed9 100644 --- a/ante/ante.go +++ b/ante/ante.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/ante" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -22,7 +21,6 @@ import ( type HandlerOptions struct { ante.HandlerOptions Codec codec.BinaryCodec - GovKeeper *govkeeper.Keeper IBCkeeper *ibckeeper.Keeper GlobalFeeSubspace paramtypes.Subspace StakingKeeper *stakingkeeper.Keeper @@ -50,9 +48,6 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { if opts.StakingKeeper == nil { return nil, errorsmod.Wrap(gaiaerrors.ErrNotFound, "staking param store is required for AnteHandler") } - if opts.GovKeeper == nil { - return nil, errorsmod.Wrap(gaiaerrors.ErrLogic, "gov keeper is required for AnteHandler") - } sigGasConsumer := opts.SigGasConsumer if sigGasConsumer == nil { @@ -66,7 +61,6 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(opts.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(opts.AccountKeeper), - NewGovPreventSpamDecorator(opts.Codec, opts.GovKeeper), gaiafeeante.NewFeeDecorator(opts.GlobalFeeSubspace, opts.StakingKeeper), ante.NewDeductFeeDecorator(opts.AccountKeeper, opts.BankKeeper, opts.FeegrantKeeper, opts.TxFeeChecker), ante.NewSetPubKeyDecorator(opts.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators diff --git a/ante/gov_ante.go b/ante/gov_ante.go deleted file mode 100644 index ba91100fc7e..00000000000 --- a/ante/gov_ante.go +++ /dev/null @@ -1,98 +0,0 @@ -package ante - -import ( - errorsmod "cosmossdk.io/errors" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/authz" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" - govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - gaiaerrors "github.com/cosmos/gaia/v15/types/errors" -) - -// initial deposit must be greater than or equal to 10% of the minimum deposit -var minInitialDepositFraction = sdk.NewDecWithPrec(10, 2) - -type GovPreventSpamDecorator struct { - govKeeper *govkeeper.Keeper - cdc codec.BinaryCodec -} - -func NewGovPreventSpamDecorator(cdc codec.BinaryCodec, govKeeper *govkeeper.Keeper) GovPreventSpamDecorator { - return GovPreventSpamDecorator{ - govKeeper: govKeeper, - cdc: cdc, - } -} - -func (g GovPreventSpamDecorator) AnteHandle( - ctx sdk.Context, tx sdk.Tx, - simulate bool, next sdk.AnteHandler, -) (newCtx sdk.Context, err error) { - // run checks only on CheckTx or simulate - if !ctx.IsCheckTx() || simulate { - return next(ctx, tx, simulate) - } - - msgs := tx.GetMsgs() - if err = g.ValidateGovMsgs(ctx, msgs); err != nil { - return ctx, err - } - - return next(ctx, tx, simulate) -} - -// validateGovMsgs checks if the InitialDeposit amounts are greater than the minimum initial deposit amount -func (g GovPreventSpamDecorator) ValidateGovMsgs(ctx sdk.Context, msgs []sdk.Msg) error { - validMsg := func(m sdk.Msg) error { - if msg, ok := m.(*govv1beta1.MsgSubmitProposal); ok { - // prevent messages with insufficient initial deposit amount - params := g.govKeeper.GetParams(ctx) - minInitialDeposit := g.calcMinInitialDeposit(params.MinDeposit) - if !msg.InitialDeposit.IsAllGTE(minInitialDeposit) { - return errorsmod.Wrapf(gaiaerrors.ErrInsufficientFunds, "insufficient initial deposit amount - required: %v", minInitialDeposit) - } - } - - return nil - } - - validAuthz := func(execMsg *authz.MsgExec) error { - for _, v := range execMsg.Msgs { - var innerMsg sdk.Msg - if err := g.cdc.UnpackAny(v, &innerMsg); err != nil { - return errorsmod.Wrap(gaiaerrors.ErrUnauthorized, "cannot unmarshal authz exec msgs") - } - if err := validMsg(innerMsg); err != nil { - return err - } - } - - return nil - } - - for _, m := range msgs { - if msg, ok := m.(*authz.MsgExec); ok { - if err := validAuthz(msg); err != nil { - return err - } - continue - } - - // validate normal msgs - if err := validMsg(m); err != nil { - return err - } - } - return nil -} - -func (g GovPreventSpamDecorator) calcMinInitialDeposit(minDeposit sdk.Coins) (minInitialDeposit sdk.Coins) { - for _, coin := range minDeposit { - minInitialCoins := minInitialDepositFraction.MulInt(coin.Amount).RoundInt() - minInitialDeposit = minInitialDeposit.Add(sdk.NewCoin(coin.Denom, minInitialCoins)) - } - return -} diff --git a/ante/gov_ante_test.go b/ante/gov_ante_test.go deleted file mode 100644 index 6bd386d2a9f..00000000000 --- a/ante/gov_ante_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package ante_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/suite" - - tmrand "github.com/cometbft/cometbft/libs/rand" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/cosmos/gaia/v15/ante" - gaiaapp "github.com/cosmos/gaia/v15/app" - gaiahelpers "github.com/cosmos/gaia/v15/app/helpers" -) - -var ( - insufficientCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 100)) - insufficientMultiDenomCoins = sdk.NewCoins( - sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - sdk.NewInt64Coin("ibc/example", 100)) - minCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)) - moreThanMinCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 2500000)) - moreThanMinMultiDenomCoins = sdk.NewCoins( - sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000), - sdk.NewInt64Coin("ibc/example", 100)) - testAddr = sdk.AccAddress("test1") -) - -type GovAnteHandlerTestSuite struct { - suite.Suite - - app *gaiaapp.GaiaApp - ctx sdk.Context - clientCtx client.Context -} - -func (s *GovAnteHandlerTestSuite) SetupTest() { - app := gaiahelpers.Setup(s.T()) - ctx := app.BaseApp.NewContext(false, tmproto.Header{ - ChainID: fmt.Sprintf("test-chain-%s", tmrand.Str(4)), - Height: 1, - }) - - legacyAmino := app.LegacyAmino() - legacyAmino.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) - testdata.RegisterInterfaces(app.InterfaceRegistry()) - - s.app = app - s.ctx = ctx - s.clientCtx = client.Context{}.WithTxConfig(app.GetTxConfig()) -} - -func TestGovSpamPreventionSuite(t *testing.T) { - suite.Run(t, new(GovAnteHandlerTestSuite)) -} - -func (s *GovAnteHandlerTestSuite) TestGlobalFeeMinimumGasFeeAnteHandler() { - // setup test - s.SetupTest() - tests := []struct { - title, description string - proposalType string - proposerAddr sdk.AccAddress - initialDeposit sdk.Coins - expectPass bool - }{ - {"Passing proposal 1", "the purpose of this proposal is to pass", govv1beta1.ProposalTypeText, testAddr, minCoins, true}, - {"Passing proposal 2", "the purpose of this proposal is to pass with more coins than minimum", govv1beta1.ProposalTypeText, testAddr, moreThanMinCoins, true}, - {"Passing proposal 3", "the purpose of this proposal is to pass with multi denom coins", govv1beta1.ProposalTypeText, testAddr, moreThanMinMultiDenomCoins, true}, - {"Failing proposal 1", "the purpose of this proposal is to fail", govv1beta1.ProposalTypeText, testAddr, insufficientCoins, false}, - {"Failing proposal 2", "the purpose of this proposal is to fail with multi denom coins", govv1beta1.ProposalTypeText, testAddr, insufficientMultiDenomCoins, false}, - } - - decorator := ante.NewGovPreventSpamDecorator(s.app.AppCodec(), s.app.GovKeeper) - - for _, tc := range tests { - content, _ := govv1beta1.ContentFromProposalType(tc.title, tc.description, tc.proposalType) - s.Require().NotNil(content) - - msg, err := govv1beta1.NewMsgSubmitProposal( - content, - tc.initialDeposit, - tc.proposerAddr, - ) - - s.Require().NoError(err) - - err = decorator.ValidateGovMsgs(s.ctx, []sdk.Msg{msg}) - if tc.expectPass { - s.Require().NoError(err, "expected %v to pass", tc.title) - } else { - s.Require().Error(err, "expected %v to fail", tc.title) - } - } -} diff --git a/app/app.go b/app/app.go index 744e9987a5f..9165aaeb977 100644 --- a/app/app.go +++ b/app/app.go @@ -225,7 +225,6 @@ func NewGaiaApp( }, Codec: appCodec, IBCkeeper: app.IBCKeeper, - GovKeeper: app.GovKeeper, GlobalFeeSubspace: app.GetSubspace(globalfee.ModuleName), StakingKeeper: app.StakingKeeper, // If TxFeeChecker is nil the default ante TxFeeChecker is used diff --git a/app/upgrades/v15/upgrades.go b/app/upgrades/v15/upgrades.go index 2b07077ed50..fee2eb9322e 100644 --- a/app/upgrades/v15/upgrades.go +++ b/app/upgrades/v15/upgrades.go @@ -15,6 +15,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -57,6 +58,9 @@ func CreateUpgradeHandler( keepers); err != nil { return nil, fmt.Errorf("failed migrating vesting funds: %s", err) } + if err := SetMinInitialDepositRatio(ctx, *keepers.GovKeeper); err != nil { + return nil, fmt.Errorf("failed initializing the min initial deposit ratio: %s", err) + } ctx.Logger().Info("Upgrade v15 complete") return vm, err @@ -323,3 +327,21 @@ func setBalance( return nil } + +// SetMinInitialDepositRatio sets the MinInitialDepositRatio param of the gov +// module to 10% - this is the proportion of the deposit value that must be paid +// at proposal submission. +func SetMinInitialDepositRatio(ctx sdk.Context, gk govkeeper.Keeper) error { + ctx.Logger().Info("Initializing MinInitialDepositRatio...") + + params := gk.GetParams(ctx) + params.MinInitialDepositRatio = sdk.NewDecWithPrec(1, 1).String() // 0.1 (10%) + err := gk.SetParams(ctx, params) + if err != nil { + return err + } + + ctx.Logger().Info("Finished initializing MinInitialDepositRatio...") + + return nil +} diff --git a/app/upgrades/v15/upgrades_test.go b/app/upgrades/v15/upgrades_test.go index 5d2c6723b1c..a6ce2e757b9 100644 --- a/app/upgrades/v15/upgrades_test.go +++ b/app/upgrades/v15/upgrades_test.go @@ -270,3 +270,16 @@ func TestClawbackVestingFunds(t *testing.T) { ) require.NoError(t, err) } + +func TestSetMinInitialDepositRatio(t *testing.T) { + gaiaApp := helpers.Setup(t) + ctx := gaiaApp.NewUncachedContext(true, tmproto.Header{}) + + err := v15.SetMinInitialDepositRatio(ctx, *gaiaApp.GovKeeper) + require.NoError(t, err) + + minInitialDepositRatioStr := gaiaApp.GovKeeper.GetParams(ctx).MinInitialDepositRatio + minInitialDepositRatio, err := math.LegacyNewDecFromStr(minInitialDepositRatioStr) + require.NoError(t, err) + require.True(t, minInitialDepositRatio.Equal(sdk.NewDecWithPrec(1, 1))) +}