diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 62bc9891b..23d653afd 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -16,6 +16,7 @@ import ( ) var _ sdk.AnteDecorator = FeeDecorator{} +var maxGasPercent = sdkmath.LegacyNewDecWithPrec(10, 2) // 10% type GlobalFeeReaderExpected interface { GetContractAuthorization(ctx sdk.Context, contractAddr sdk.AccAddress) (types.ContractAuthorization, error) @@ -57,26 +58,43 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne msgs := feeTx.GetMsgs() // currently accepting zero fee transactions only when the tx contains only the authorized operations that can bypass the minimum fee - onlyZeroFeeMsgs := mfd.containsOnlyZeroFeeMsgs(ctx, msgs) + onlyFreeMsgs, atLeastOneFreeMsg := mfd.freeMsgsCheck(ctx, msgs) - return mfd.checkFees(ctx, feeTx, tx, onlyZeroFeeMsgs, simulate, next) // https://github.com/cosmos/gaia/blob/6fe097e3280baa360a28b59a29b8cca964a5ae97/x/globalfee/ante/fee.go + if atLeastOneFreeMsg { + maxGas := sdkmath.LegacyNewDec(ctx.ConsensusParams().Block.MaxGas).Mul(maxGasPercent) + if feeTx.GetGas() > uint64(maxGas.RoundInt64()) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidGasLimit, "overallocated gas value") + } + } + return mfd.checkFees(ctx, feeTx, tx, onlyFreeMsgs, simulate, next) // https://github.com/cosmos/gaia/blob/6fe097e3280baa360a28b59a29b8cca964a5ae97/x/globalfee/ante/fee.go } -func (mfd FeeDecorator) containsOnlyZeroFeeMsgs(ctx sdk.Context, msgs []sdk.Msg) bool { +func (mfd FeeDecorator) freeMsgsCheck(ctx sdk.Context, msgs []sdk.Msg) (onlyFreeMsgs, atLeastOneFreeMsg bool) { + totalMsgs := len(msgs) + freeMsgs := 0 + for _, m := range msgs { switch msg := m.(type) { case *wasmtypes.MsgExecuteContract: { - if !mfd.isZeroFeeMsg(ctx, msg) { - return false + if mfd.isZeroFeeMsg(ctx, msg) { + freeMsgs++ + atLeastOneFreeMsg = true + } else { + onlyFreeMsgs = false + return onlyFreeMsgs, atLeastOneFreeMsg } + } default: - return false + return false, atLeastOneFreeMsg } } + if freeMsgs == totalMsgs { + return true, true + } - return true + return false, atLeastOneFreeMsg } func (mfd FeeDecorator) isZeroFeeMsg(ctx sdk.Context, msg *wasmtypes.MsgExecuteContract) bool { diff --git a/x/globalfee/ante/fee_setup_test.go b/x/globalfee/ante/fee_setup_test.go index 4ec892352..033ffe498 100644 --- a/x/globalfee/ante/fee_setup_test.go +++ b/x/globalfee/ante/fee_setup_test.go @@ -63,7 +63,11 @@ func (s *AnteHandlerTestSuite) SetupTest() { } app := simapp.SetupWithGenesisAccounts(s.T(), s.T().TempDir(), genAccounts, genBalances...) h := cmtproto.Header{Height: app.LastBlockHeight() + 1} - ctx := sdk.NewContext(app.CommitMultiStore(), h, false, app.Logger()).WithBlockTime(time.Now()) + ctx := sdk.NewContext(app.CommitMultiStore(), h, false, app.Logger()).WithBlockTime(time.Now()).WithConsensusParams(cmtproto.ConsensusParams{ + Block: &cmtproto.BlockParams{ + MaxGas: 225_000_000, // 225M + }, + }) encodingConfig := stargazeapp.MakeEncodingConfig() @@ -76,7 +80,11 @@ func (s *AnteHandlerTestSuite) SetupTestGlobalFeeStoreAndMinGasPrice(minGasPrice err := s.app.Keepers.GlobalFeeKeeper.SetParams(s.ctx, types.Params{MinimumGasPrices: globalFees}) s.Require().NoError(err) - s.ctx = s.ctx.WithMinGasPrices(minGasPrice).WithIsCheckTx(true) + s.ctx = s.ctx.WithMinGasPrices(minGasPrice).WithIsCheckTx(true).WithConsensusParams(cmtproto.ConsensusParams{ + Block: &cmtproto.BlockParams{ + MaxGas: 225_000_000, // 225M + }, + }) // build fee decorator feeDecorator := ante.NewFeeDecorator(s.app.AppCodec(), s.app.Keepers.GlobalFeeKeeper, s.app.Keepers.StakingKeeper) diff --git a/x/globalfee/ante/fee_test.go b/x/globalfee/ante/fee_test.go index 595d0b2e0..3d651919f 100644 --- a/x/globalfee/ante/fee_test.go +++ b/x/globalfee/ante/fee_test.go @@ -34,6 +34,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { feeSent sdk.Coins // the amount of fee sent by the user in the tx msg []sdk.Msg expectErr bool + gasWanted int64 }{ { "fail: min_gas_price: empty, globalfee: 5stake, feeSent: 1stake, not authorized contract exec", @@ -48,6 +49,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, true, + 1, }, { "ok: min_gas_price: empty, globalfee: 5stake, feeSent: 7stake, not authorized contract exec", @@ -62,6 +64,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "fail: min_gas_price: 0stake, globalfee: 5stake, feeSent: 0stake, not authorized contract exec", @@ -76,6 +79,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, true, + 1, }, { "ok: min_gas_price: 0stake, globalfee: 5stake, feeSent: 5stake, not authorized contract exec", @@ -90,6 +94,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "fail: min_gas_price: 2stake, globalfee: 5stake, feeSent: 1stake, not authorized contract exec", @@ -104,6 +109,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, true, + 1, }, { "fail: min_gas_price: 2stake, globalfee: 5stake, feeSent: 3stake, not authorized contract exec", @@ -118,6 +124,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, true, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 5stake, not authorized contract exec", @@ -132,6 +139,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, authorized code id", @@ -146,6 +154,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "fail: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, authorized contract address but not auth msg", @@ -160,6 +169,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, true, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, authorized contract address with auth msg", @@ -174,6 +184,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, authorized contract address with auth all (*)", @@ -188,6 +199,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, authorized contract address with auth all (*)", @@ -202,6 +214,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, multiple authorized contract calls", @@ -226,6 +239,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, }, { "fail: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, one authorized contract + unauthorized msgs", @@ -250,6 +264,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, true, + 1, }, { "ok: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, one authorized contract + unauthorized msgs", @@ -269,6 +284,22 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { }, }, false, + 1, + }, + { + "fail: min_gas_price: 2stake, globalfee: 5stake, feeSent: 0stake, authorized code id but overallocated gas", + sdk.NewDecCoins(sdk.NewInt64DecCoin(sdk.DefaultBondDenom, 2)), + sdk.NewDecCoins(sdk.NewInt64DecCoin(sdk.DefaultBondDenom, 5)), + sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)), + []sdk.Msg{ + &wasmtypes.MsgExecuteContract{ + Sender: addr1.String(), + Contract: contractWithCodeAuth, + Msg: counterIncrementMsg, + }, + }, + true, + 50_000_000, }, } @@ -277,7 +308,7 @@ func (s *AnteHandlerTestSuite) TestFeeDecoratorAntehandler() { _, antehandler := s.SetupTestGlobalFeeStoreAndMinGasPrice(tc.minGasPrice, tc.globalFees) s.Require().NoError(s.txBuilder.SetMsgs(tc.msg...)) s.txBuilder.SetFeeAmount(tc.feeSent) - s.txBuilder.SetGasLimit(1) + s.txBuilder.SetGasLimit(uint64(tc.gasWanted)) tx, err := s.CreateTestTx(s.ctx, privs, accNums, accSeqs, s.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT) s.Require().NoError(err)