-
Notifications
You must be signed in to change notification settings - Fork 697
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add spam prevention antehandler (#2262)
* add spam prevention antehandler * sort imports * run make format * fix misleading var names * update wrong test cases * fix failing gov tests * fix linter errors * uncomment e2e gov steps logs
- Loading branch information
Showing
7 changed files
with
235 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package ante | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/x/authz" | ||
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" | ||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" | ||
) | ||
|
||
// 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.(*govtypes.MsgSubmitProposal); ok { | ||
// prevent messages with insufficient initial deposit amount | ||
depositParams := g.govKeeper.GetDepositParams(ctx) | ||
minInitialDeposit := g.calcMinInitialDeposit(depositParams.MinDeposit) | ||
if msg.InitialDeposit.IsAllLT(minInitialDeposit) { | ||
return sdkerrors.Wrapf(sdkerrors.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 sdkerrors.Wrapf(sdkerrors.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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package ante_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" | ||
"github.com/stretchr/testify/suite" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
"github.com/cosmos/cosmos-sdk/testutil/testdata" | ||
"github.com/cosmos/gaia/v9/ante" | ||
gaiahelpers "github.com/cosmos/gaia/v9/app/helpers" | ||
tmrand "github.com/tendermint/tendermint/libs/rand" | ||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||
|
||
gaiaapp "github.com/cosmos/gaia/v9/app" | ||
) | ||
|
||
var ( | ||
insufficientCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 100)) | ||
minCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)) | ||
moreThanMinCoins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 2500000)) | ||
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, | ||
}) | ||
|
||
encodingConfig := gaiaapp.MakeTestEncodingConfig() | ||
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) | ||
testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry) | ||
|
||
s.app = app | ||
s.ctx = ctx | ||
s.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig) | ||
} | ||
|
||
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", govtypes.ProposalTypeText, testAddr, minCoins, true}, | ||
{"Passing proposal 2", "the purpose of this proposal is to pass with more coins than minimum", govtypes.ProposalTypeText, testAddr, moreThanMinCoins, true}, | ||
{"Failing proposal", "the purpose of this proposal is to fail", govtypes.ProposalTypeText, testAddr, insufficientCoins, false}, | ||
} | ||
|
||
decorator := ante.NewGovPreventSpamDecorator(s.app.AppCodec(), &s.app.GovKeeper) | ||
|
||
for _, tc := range tests { | ||
content := govtypes.ContentFromProposalType(tc.title, tc.description, tc.proposalType) | ||
s.Require().NotNil(content) | ||
|
||
msg, err := govtypes.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) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters