Skip to content

Commit 83e509b

Browse files
refactor: optimize AnteHandler gas consumption (evmos#1388)
* refactor: antehandler order and params optimization * removed additional individual params for the feemarket module * typo fix * Apply suggestions from code review - Fede Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * typo fix * formatted using gofumpt * typo fix - missed negate operator * missed to negate conditions * added unit tests for the new param getter methods * updated changelog * Apply suggestions from code review Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * moved to improvements * Converted unit tests into table-driven tests * added Require().Equal() to test case Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
1 parent 5879750 commit 83e509b

19 files changed

+258
-66
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
5252

5353
### Improvements
5454

55+
* (ante) [\#1388](https://github.com/evmos/ethermint/pull/1388) Optimize AnteHandler gas consumption
5556
* (lint) [#1298](https://github.com/evmos/ethermint/pull/1298) 150 character line length limit, `gofumpt`, and linting
5657
* (feemarket) [\#1165](https://github.com/evmos/ethermint/pull/1165) Add hint in specs about different gas terminology in Cosmos and Ethereum.
5758
* (cli) [#1226](https://github.com/evmos/ethermint/pull/1226) Add custom app db backend flag.

app/ante/ante_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
344344
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
345345
gasAmount := sdk.NewCoins(coinAmount)
346346
gas := uint64(200000)
347-
//reusing the gasAmount for deposit
347+
// reusing the gasAmount for deposit
348348
deposit := sdk.NewCoins(coinAmount)
349349
txBuilder := suite.CreateTestEIP712SubmitProposal(from, privKey, "ethermint_9000-1", gas, gasAmount, deposit)
350350
return txBuilder.GetTx()

app/ante/eth.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
4040
// won't see the error message.
4141
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
4242
chainID := esvd.evmKeeper.ChainID()
43-
44-
params := esvd.evmKeeper.GetParams(ctx)
45-
46-
ethCfg := params.ChainConfig.EthereumConfig(chainID)
43+
chainCfg := esvd.evmKeeper.GetChainConfig(ctx)
44+
ethCfg := chainCfg.EthereumConfig(chainID)
4745
blockNum := big.NewInt(ctx.BlockHeight())
4846
signer := ethtypes.MakeSigner(ethCfg, blockNum)
4947

@@ -53,8 +51,9 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
5351
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
5452
}
5553

54+
allowUnprotectedTxs := esvd.evmKeeper.GetAllowUnprotectedTxs(ctx)
5655
ethTx := msgEthTx.AsTransaction()
57-
if !params.AllowUnprotectedTxs && !ethTx.Protected() {
56+
if !allowUnprotectedTxs && !ethTx.Protected() {
5857
return ctx, sdkerrors.Wrapf(
5958
sdkerrors.ErrNotSupported,
6059
"rejected unprotected Ethereum txs. Please EIP155 sign your transaction to protect it against replay-attacks")
@@ -176,15 +175,13 @@ func NewEthGasConsumeDecorator(
176175
// - transaction or block gas meter runs out of gas
177176
// - sets the gas meter limit
178177
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
179-
params := egcd.evmKeeper.GetParams(ctx)
180-
181-
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
178+
chainCfg := egcd.evmKeeper.GetChainConfig(ctx)
179+
ethCfg := chainCfg.EthereumConfig(egcd.evmKeeper.ChainID())
182180

183181
blockHeight := big.NewInt(ctx.BlockHeight())
184182
homestead := ethCfg.IsHomestead(blockHeight)
185183
istanbul := ethCfg.IsIstanbul(blockHeight)
186184
london := ethCfg.IsLondon(blockHeight)
187-
evmDenom := params.EvmDenom
188185
gasWanted := uint64(0)
189186
var events sdk.Events
190187

@@ -213,6 +210,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
213210
gasWanted += txData.GetGas()
214211
}
215212

213+
evmDenom := egcd.evmKeeper.GetEVMDenom(ctx)
216214
fees, priority, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
217215
ctx,
218216
*msgEthTx,
@@ -436,9 +434,9 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
436434
txFee := sdk.Coins{}
437435
txGasLimit := uint64(0)
438436

439-
params := vbd.evmKeeper.GetParams(ctx)
437+
chainCfg := vbd.evmKeeper.GetChainConfig(ctx)
440438
chainID := vbd.evmKeeper.ChainID()
441-
ethCfg := params.ChainConfig.EthereumConfig(chainID)
439+
ethCfg := chainCfg.EthereumConfig(chainID)
442440
baseFee := vbd.evmKeeper.GetBaseFee(ctx, ethCfg)
443441

444442
for _, msg := range protoTx.GetMsgs() {
@@ -460,17 +458,21 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
460458
}
461459

462460
// return error if contract creation or call are disabled through governance
463-
if !params.EnableCreate && txData.GetTo() == nil {
461+
enableCreate := vbd.evmKeeper.GetEnableCreate(ctx)
462+
enableCall := vbd.evmKeeper.GetEnableCall(ctx)
463+
464+
if !enableCreate && txData.GetTo() == nil {
464465
return ctx, sdkerrors.Wrap(evmtypes.ErrCreateDisabled, "failed to create new contract")
465-
} else if !params.EnableCall && txData.GetTo() != nil {
466+
} else if !enableCall && txData.GetTo() != nil {
466467
return ctx, sdkerrors.Wrap(evmtypes.ErrCallDisabled, "failed to call contract")
467468
}
468469

469470
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
470471
return ctx, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
471472
}
472473

473-
txFee = txFee.Add(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
474+
evmDenom := vbd.evmKeeper.GetEVMDenom(ctx)
475+
txFee = txFee.Add(sdk.NewCoin(evmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
474476
}
475477

476478
authInfo := protoTx.AuthInfo
@@ -546,8 +548,8 @@ func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
546548
// It only do the check if london hardfork not enabled or feemarket not enabled, because in that case feemarket will take over the task.
547549
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
548550
if ctx.IsCheckTx() && !simulate {
549-
params := mfd.evmKeeper.GetParams(ctx)
550-
ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
551+
chainCfg := mfd.evmKeeper.GetChainConfig(ctx)
552+
ethCfg := chainCfg.EthereumConfig(mfd.evmKeeper.ChainID())
551553
baseFee := mfd.evmKeeper.GetBaseFee(ctx, ethCfg)
552554
if baseFee == nil {
553555
for _, msg := range tx.GetMsgs() {
@@ -556,7 +558,7 @@ func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat
556558
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
557559
}
558560

559-
evmDenom := params.EvmDenom
561+
evmDenom := mfd.evmKeeper.GetEVMDenom(ctx)
560562
feeAmt := ethMsg.GetFee()
561563
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
562564
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)

app/ante/fee_market.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func NewGasWantedDecorator(
2727
}
2828

2929
func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
30-
params := gwd.evmKeeper.GetParams(ctx)
31-
ethCfg := params.ChainConfig.EthereumConfig(gwd.evmKeeper.ChainID())
30+
chainCfg := gwd.evmKeeper.GetChainConfig(ctx)
31+
ethCfg := chainCfg.EthereumConfig(gwd.evmKeeper.ChainID())
3232

3333
blockHeight := big.NewInt(ctx.BlockHeight())
3434
isLondon := ethCfg.IsLondon(blockHeight)
@@ -39,10 +39,10 @@ func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
3939
}
4040

4141
gasWanted := feeTx.GetGas()
42-
feeMktParams := gwd.feeMarketKeeper.GetParams(ctx)
42+
isBaseFeeEnabled := gwd.feeMarketKeeper.GetBaseFeeEnabled(ctx)
4343

4444
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
45-
if feeMktParams.IsBaseFeeEnabled(ctx.BlockHeight()) {
45+
if isBaseFeeEnabled {
4646
if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil {
4747
return ctx, sdkerrors.Wrapf(err, "failed to add gas wanted to transient store")
4848
}

app/ante/fees.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
3737
return next(ctx, tx, simulate)
3838
}
3939

40-
evmParams := mpd.evmKeeper.GetParams(ctx)
40+
evmDenom := mpd.evmKeeper.GetEVMDenom(ctx)
4141
minGasPrices := sdk.DecCoins{
4242
{
43-
Denom: evmParams.EvmDenom,
43+
Denom: evmDenom,
4444
Amount: minGasPrice,
4545
},
4646
}
@@ -93,8 +93,8 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
9393
return next(ctx, tx, simulate)
9494
}
9595

96-
paramsEvm := empd.evmKeeper.GetParams(ctx)
97-
ethCfg := paramsEvm.ChainConfig.EthereumConfig(empd.evmKeeper.ChainID())
96+
chainCfg := empd.evmKeeper.GetChainConfig(ctx)
97+
ethCfg := chainCfg.EthereumConfig(empd.evmKeeper.ChainID())
9898
baseFee := empd.evmKeeper.GetBaseFee(ctx, ethCfg)
9999

100100
for _, msg := range tx.GetMsgs() {

app/ante/handler_options.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type HandlerOptions struct {
2020
AccountKeeper evmtypes.AccountKeeper
2121
BankKeeper evmtypes.BankKeeper
2222
IBCKeeper *ibckeeper.Keeper
23-
FeeMarketKeeper evmtypes.FeeMarketKeeper
23+
FeeMarketKeeper FeeMarketKeeper
2424
EvmKeeper EVMKeeper
2525
FeegrantKeeper ante.FeegrantKeeper
2626
SignModeHandler authsigning.SignModeHandler
@@ -70,9 +70,9 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
7070
RejectMessagesDecorator{}, // reject MsgEthereumTxs
7171
ante.NewSetUpContextDecorator(),
7272
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
73-
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
7473
ante.NewValidateBasicDecorator(),
7574
ante.NewTxTimeoutHeightDecorator(),
75+
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
7676
ante.NewValidateMemoDecorator(options.AccountKeeper),
7777
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
7878
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
@@ -93,9 +93,9 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
9393
ante.NewSetUpContextDecorator(),
9494
// NOTE: extensions option decorator removed
9595
// ante.NewRejectExtensionOptionsDecorator(),
96-
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
9796
ante.NewValidateBasicDecorator(),
9897
ante.NewTxTimeoutHeightDecorator(),
98+
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
9999
ante.NewValidateMemoDecorator(options.AccountKeeper),
100100
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
101101
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),

app/ante/interfaces.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ type EVMKeeper interface {
3434
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
3535
ResetTransientGasUsed(ctx sdk.Context)
3636
GetTxIndexTransient(ctx sdk.Context) uint64
37+
GetChainConfig(ctx sdk.Context) evmtypes.ChainConfig
38+
GetEVMDenom(ctx sdk.Context) string
39+
GetEnableCreate(ctx sdk.Context) bool
40+
GetEnableCall(ctx sdk.Context) bool
41+
GetAllowUnprotectedTxs(ctx sdk.Context) bool
3742
}
3843

3944
type protoTxProvider interface {
@@ -44,4 +49,5 @@ type protoTxProvider interface {
4449
type FeeMarketKeeper interface {
4550
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
4651
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
52+
GetBaseFeeEnabled(ctx sdk.Context) bool
4753
}

ethereum/eip712/preprocess_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ import (
2323
)
2424

2525
// Testing Constants
26-
var chainId = "ethermint_9000-1"
27-
var ctx = client.Context{}.WithTxConfig(
28-
encoding.MakeConfig(app.ModuleBasics).TxConfig,
26+
var (
27+
chainId = "ethermint_9000-1"
28+
ctx = client.Context{}.WithTxConfig(
29+
encoding.MakeConfig(app.ModuleBasics).TxConfig,
30+
)
2931
)
3032
var feePayerAddress = "ethm17xpfvakm2amg962yls6f84z3kell8c5lthdzgl"
3133

tests/rpc/ws_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ package rpc
33
import (
44
"encoding/json"
55
"fmt"
6-
"github.com/gorilla/websocket"
7-
"github.com/stretchr/testify/require"
86
"net/url"
97
"os"
108
"strings"
119
"testing"
1210
"time"
11+
12+
"github.com/gorilla/websocket"
13+
"github.com/stretchr/testify/require"
1314
)
1415

1516
var (

x/evm/keeper/params.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,38 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
2121
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
2222
k.paramSpace.SetParamSet(ctx, &params)
2323
}
24+
25+
// GetChainConfig returns the chain configuration parameter.
26+
func (k Keeper) GetChainConfig(ctx sdk.Context) types.ChainConfig {
27+
chainCfg := types.ChainConfig{}
28+
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyChainConfig, &chainCfg)
29+
return chainCfg
30+
}
31+
32+
// GetEVMDenom returns the EVM denom.
33+
func (k Keeper) GetEVMDenom(ctx sdk.Context) string {
34+
evmDenom := ""
35+
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyEVMDenom, &evmDenom)
36+
return evmDenom
37+
}
38+
39+
// GetEnableCall returns true if the EVM Call operation is enabled.
40+
func (k Keeper) GetEnableCall(ctx sdk.Context) bool {
41+
enableCall := false
42+
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyEnableCall, &enableCall)
43+
return enableCall
44+
}
45+
46+
// GetEnableCreate returns true if the EVM Create contract operation is enabled.
47+
func (k Keeper) GetEnableCreate(ctx sdk.Context) bool {
48+
enableCreate := false
49+
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyEnableCreate, &enableCreate)
50+
return enableCreate
51+
}
52+
53+
// GetAllowUnprotectedTxs returns true if unprotected txs (i.e non-replay protected as per EIP-155) are supported by the chain.
54+
func (k Keeper) GetAllowUnprotectedTxs(ctx sdk.Context) bool {
55+
allowUnprotectedTx := false
56+
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyAllowUnprotectedTxs, &allowUnprotectedTx)
57+
return allowUnprotectedTx
58+
}

0 commit comments

Comments
 (0)