diff --git a/CHANGELOG.md b/CHANGELOG.md index 956f7a95..dec0b54f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (evm) [#1444](https://github.com/evmos/ethermint/pull/1444) Improve performance of `eth_estimateGas` * (ante) [\#1388](https://github.com/evmos/ethermint/pull/1388) Optimize AnteHandler gas consumption * (lint) [#1298](https://github.com/evmos/ethermint/pull/1298) 150 character line length limit, `gofumpt`, and linting * (feemarket) [\#1165](https://github.com/evmos/ethermint/pull/1165) Add hint in specs about different gas terminology in Cosmos and Ethereum. diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index b5189e42..5923987f 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -305,14 +305,31 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) - // Create a helper to check if a gas allowance results in an executable transaction - executable := func(gas uint64) (vmerror bool, rsp *types.MsgEthereumTxResponse, err error) { - args.Gas = (*hexutil.Uint64)(&gas) + // convert the tx args to an ethereum message + msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } - msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) - if err != nil { - return false, nil, err - } + // NOTE: the errors from the executable below should be consistent with go-ethereum, + // so we don't wrap them with the gRPC status code + + // Create a helper to check if a gas allowance results in an executable transaction + executable := func(gas uint64) (vmError bool, rsp *types.MsgEthereumTxResponse, err error) { + // update the message with the new gas value + msg = ethtypes.NewMessage( + msg.From(), + msg.To(), + msg.Nonce(), + msg.Value(), + gas, + msg.GasPrice(), + msg.GasFeeCap(), + msg.GasTipCap(), + msg.Data(), + msg.AccessList(), + msg.IsFake(), + ) // pass false to not commit StateDB rsp, err = k.ApplyMessageWithConfig(ctx, msg, nil, false, cfg, txConfig) @@ -328,24 +345,25 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type // Execute the binary search and hone in on an executable gas limit hi, err = types.BinSearch(lo, hi, executable) if err != nil { - return nil, status.Error(codes.Internal, err.Error()) + return nil, err } // Reject the transaction as invalid if it still fails at the highest allowance if hi == cap { failed, result, err := executable(hi) if err != nil { - return nil, status.Error(codes.Internal, err.Error()) + return nil, err } + if failed { if result != nil && result.VmError != vm.ErrOutOfGas.Error() { if result.VmError == vm.ErrExecutionReverted.Error() { return nil, types.NewExecErrorWithReason(result.Ret) } - return nil, status.Error(codes.Internal, result.VmError) + return nil, errors.New(result.VmError) } // Otherwise, the specified gas cap is too low - return nil, status.Error(codes.Internal, fmt.Sprintf("gas required exceeds allowance (%d)", cap)) + return nil, fmt.Errorf("gas required exceeds allowance (%d)", cap) } } return &types.EstimateGasResponse{Gas: hi}, nil