From 6d19120d2ff996932fab3952b318e6072bfb2d05 Mon Sep 17 00:00:00 2001 From: yys Date: Wed, 17 Mar 2021 12:35:22 +0900 Subject: [PATCH] [Feature] add tx-gas-hard-limit flag to prevent spamming attack (#460) * add tx-gas-hard-limit flag to prevent spamming attack * convert spamming protection to mempool operation --- cmd/terrad/main.go | 7 ++++++ x/auth/ante/ante.go | 3 ++- x/auth/ante/spamming_prevention.go | 38 ++++++++++++++++++++++++++++++ x/auth/ante/tax.go | 2 +- 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 x/auth/ante/spamming_prevention.go diff --git a/cmd/terrad/main.go b/cmd/terrad/main.go index 61052e7ea..6f26c09eb 100644 --- a/cmd/terrad/main.go +++ b/cmd/terrad/main.go @@ -28,6 +28,7 @@ import ( genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/terra-project/core/x/auth" + coreante "github.com/terra-project/core/x/auth/ante" "github.com/terra-project/core/x/staking" wasmconfig "github.com/terra-project/core/x/wasm/config" ) @@ -73,6 +74,12 @@ func main() { executor := cli.PrepareBaseCmd(rootCmd, "TE", app.DefaultNodeHome) rootCmd.PersistentFlags().UintVar(&invCheckPeriod, flagInvCheckPeriod, 0, "Assert registered invariants every N blocks") + + // register tx gas hard cap flag + rootCmd.PersistentFlags().Uint64(coreante.FlagTxGasHardLimit, uint64(30000000), + "Transaction hard cap to prevent spamming attack") + viper.BindPFlag(coreante.FlagTxGasHardLimit, rootCmd.Flags().Lookup(coreante.FlagTxGasHardLimit)) + err := executor.Execute() if err != nil { panic(err) diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index 2a340182f..ecb9aaa12 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -13,7 +13,8 @@ import ( func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, treasuryKeeper TreasuryKeeper, sigGasConsumer cosmosante.SignatureVerificationGasConsumer) sdk.AnteHandler { return sdk.ChainAnteDecorators( cosmosante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first - NewTaxFeeDecorator(treasuryKeeper), // mempool gas fee validation & record tax proceeds + NewSpammingPreventionDecorator(), + NewTaxFeeDecorator(treasuryKeeper), // mempool gas fee validation & record tax proceeds cosmosante.NewValidateBasicDecorator(), cosmosante.NewValidateMemoDecorator(ak), cosmosante.NewConsumeGasForTxSizeDecorator(ak), diff --git a/x/auth/ante/spamming_prevention.go b/x/auth/ante/spamming_prevention.go new file mode 100644 index 000000000..23814ea03 --- /dev/null +++ b/x/auth/ante/spamming_prevention.go @@ -0,0 +1,38 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/spf13/viper" +) + +// FlagTxGasHardLimit defines the hard cap to prevent tx spamming attack +const FlagTxGasHardLimit = "tx-gas-hard-limit" + +// SpammingPreventionDecorator will check if the transaction's gas is smaller than +// configured hard cap +type SpammingPreventionDecorator struct { +} + +// NewSpammingPreventionDecorator returns new spamming prevention decorator instance +func NewSpammingPreventionDecorator() SpammingPreventionDecorator { + return SpammingPreventionDecorator{} +} + +// AnteHandle handles msg tax fee checking +func (spd SpammingPreventionDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + if ctx.IsCheckTx() { + feeTx, ok := tx.(FeeTx) + if !ok { + return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + gas := feeTx.GetGas() + gasHardLimit := viper.GetUint64(FlagTxGasHardLimit) + if gas > gasHardLimit { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "Tx cannot spend more than %d gas", gasHardLimit) + } + } + + return next(ctx, tx, simulate) +} diff --git a/x/auth/ante/tax.go b/x/auth/ante/tax.go index 9b006267c..018c3123d 100644 --- a/x/auth/ante/tax.go +++ b/x/auth/ante/tax.go @@ -21,7 +21,7 @@ type FeeTx interface { FeePayer() sdk.AccAddress } -// TaxDecorator will check if the transaction's fee is at least as large +// TaxFeeDecorator will check if the transaction's fee is at least as large // as tax + the local validator's minimum gasFee (defined in validator config) // and record tax proceeds to treasury module to track tax proceeds. // If fee is too low, decorator returns error and tx is rejected from mempool.