Skip to content

feat: support query gas limit flag #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [\#350](https://github.com/cosmos/evm/pull/350) Fix p256 precompile test flakiness
- [\#376](https://github.com/cosmos/evm/pull/376) Fix precompile initialization for local node development script
- [\#384](https://github.com/cosmos/evm/pull/384) Fix debug_traceTransaction RPC failing with block height mismatch errors
- [\#368](https://github.com/cosmos/evm/pull/368) Support query gas limit flag
- [\#441](https://github.com/cosmos/evm/pull/441) Align precompiles map with available static check to Prague.

### IMPROVEMENTS
Expand Down
1 change: 1 addition & 0 deletions evmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ func NewExampleApp(
&app.ConsensusParamsKeeper,
&app.Erc20Keeper,
tracer,
cast.ToUint64(appOpts.Get(server.FlagQueryGasLimit)),
Copy link
Contributor

@technicallyty technicallyty Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this flag is meant to control the cosmos SDK query gas limit. im not sure if it makes sense to use it in this way.

imo it makes more sense to set the value like this:

root.go

baseapp.SetQueryGasLimit(cast.ToUint64(appOpts.Get(sdkserver.FlagQueryGasLimit))),

this will make the SDK set a gas limit in context during query executions. then we can update the keeper calls to respect the value set here: https://github.com/cosmos/cosmos-sdk/blob/553f8955c3214c21c2755811aae5a8f3e021f0f8/baseapp/abci.go#L1282-L1286


keep in mind, this would enforce a query gas limit for ALL gRPC queries. if we want a separate gas limit (i.e. no gas limit for SDK queries, but one for EVM), i suggest we create a separate flag.

Copy link
Contributor Author

@thomas-nguy thomas-nguy Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want a separate gas limit (i.e. no gas limit for SDK queries, but one for EVM), i suggest we create a separate flag.

Do we want to support such use case? The FlagQueryGasLimit is meant to set a max gas limit for all Rest/Grpc queries, intended to prevent DOS attack
My original thought is that the x/evm module rpcs is a subset of those queries (as they all endup calling cosmos level rest/grpc) and need to follow the same limitation. Adding an extra flag may bring an additional layer of complexity, and confuse users.

I can do the change if it is really needed though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main reason i would think to separate them is because im unsure of the relation between eth gas units and SDK gas units. i know eth gas costs are quite calculated and well thought out, whereas the SDK's feels more arbitrarily chosen.

any thoughts here? @aljo242? i know youve mentioned we dont want to have too many ways to configure things these days, so maybe lets just go with a catch-all flag

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to put it under the one flag

)

app.Erc20Keeper = erc20keeper.NewKeeper(
Expand Down
1 change: 1 addition & 0 deletions evmd/cmd/evmd/cmd/creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func (a appCreator) newApp(
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))),
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))),
baseapp.SetQueryGasLimit(cast.ToUint64(appOpts.Get(server.FlagQueryGasLimit))),
}

return evmd.NewExampleApp(
Expand Down
1 change: 1 addition & 0 deletions evmd/cmd/evmd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ func newApp(
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(sdkserver.FlagIAVLCacheSize))),
baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(sdkserver.FlagDisableIAVLFastNode))),
baseapp.SetChainID(chainID),
baseapp.SetQueryGasLimit(cast.ToUint64(appOpts.Get(sdkserver.FlagQueryGasLimit))),
}

return evmd.NewExampleApp(
Expand Down
31 changes: 23 additions & 8 deletions x/vm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms
nonce := k.GetNonce(ctx, args.GetFrom())
args.Nonce = (*hexutil.Uint64)(&nonce)

if err := args.CallDefaults(req.GasCap, cfg.BaseFee, types.GetEthChainConfig().ChainID); err != nil {
gasCap := k.GlobalQueryGasLimit(req)
if err := args.CallDefaults(gasCap, cfg.BaseFee, types.GetEthChainConfig().ChainID); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}

Expand Down Expand Up @@ -291,9 +292,8 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest

// Binary search the gas requirement, as it may be higher than the amount used
var (
lo = ethparams.TxGas - 1
hi uint64
gasCap uint64
lo = ethparams.TxGas - 1
hi uint64
)

// Determine the highest gas limit can be used during the estimation.
Expand All @@ -310,11 +310,13 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest
}

// Recap the highest gas allowance with specified gascap.
if req.GasCap != 0 && hi > req.GasCap {
hi = req.GasCap
gasCap := k.GlobalQueryGasLimit(req)
if gasCap != 0 && hi > gasCap {
hi = gasCap
} else {
gasCap = hi
}

gasCap = hi
cfg, err := k.EVMConfig(ctx, GetProposerAddress(ctx, req.ProposerAddress))
if err != nil {
return nil, status.Error(codes.Internal, "failed to load evm config")
Expand All @@ -329,7 +331,7 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest
if args.Gas == nil {
args.Gas = new(hexutil.Uint64)
}
if err := args.CallDefaults(req.GasCap, cfg.BaseFee, types.GetEthChainConfig().ChainID); err != nil {
if err := args.CallDefaults(gasCap, cfg.BaseFee, types.GetEthChainConfig().ChainID); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}

Expand Down Expand Up @@ -734,6 +736,19 @@ func (k Keeper) GlobalMinGasPrice(c context.Context, _ *types.QueryGlobalMinGasP
return &types.QueryGlobalMinGasPriceResponse{MinGasPrice: minGasPrice}, nil
}

// GlobalQueryGasLimit return the minimum between server queryGasLimit and request gascap
func (k Keeper) GlobalQueryGasLimit(req *types.EthCallRequest) uint64 {
gasCap := req.GasCap
if k.queryGasLimit != GasNoLimit {
if gasCap == 0 {
gasCap = k.queryGasLimit
} else if k.queryGasLimit < gasCap {
gasCap = k.queryGasLimit
}
}
return gasCap
}

// Config implements the Query/Config gRPC method
func (k Keeper) Config(_ context.Context, _ *types.QueryConfigRequest) (*types.QueryConfigResponse, error) {
config := types.GetChainConfig()
Expand Down
8 changes: 8 additions & 0 deletions x/vm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// GasNoLimit is the value for keeper.queryGasLimit in case there is no limit
const GasNoLimit = 0

// Keeper grants access to the EVM module state and implements the go-ethereum StateDB interface.
type Keeper struct {
// Protobuf codec
Expand Down Expand Up @@ -77,6 +80,9 @@ type Keeper struct {
// parameters.
precompiles map[common.Address]vm.PrecompiledContract

// queryGasLimit max amount of gas allowed on queries, 0 means no limit
queryGasLimit uint64

// evmMempool is the custom EVM appside mempool
// if it is nil, the default comet mempool will be used
evmMempool *evmmempool.ExperimentalEVMMempool
Expand All @@ -95,6 +101,7 @@ func NewKeeper(
consensusKeeper types.ConsensusParamsKeeper,
erc20Keeper types.Erc20Keeper,
tracer string,
queryGasLimit uint64,
) *Keeper {
// ensure evm module account is set
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
Expand Down Expand Up @@ -123,6 +130,7 @@ func NewKeeper(
consensusKeeper: consensusKeeper,
erc20Keeper: erc20Keeper,
storeKeys: keys,
queryGasLimit: queryGasLimit,
}
}

Expand Down