imp(evm): improve performance of EstimateGas (#1444)

* imp(evm): improve performance of EstimateGas

* changelog
This commit is contained in:
Federico Kunze Küllmer 2022-11-09 16:11:07 +01:00 committed by GitHub
parent b820ff7a2c
commit 89fdd19848
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 11 deletions

View File

@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements ### 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 * (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 * (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. * (feemarket) [\#1165](https://github.com/evmos/ethermint/pull/1165) Add hint in specs about different gas terminology in Cosmos and Ethereum.

View File

@ -305,14 +305,31 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type
txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))
// Create a helper to check if a gas allowance results in an executable transaction // convert the tx args to an ethereum message
executable := func(gas uint64) (vmerror bool, rsp *types.MsgEthereumTxResponse, err error) { msg, err := args.ToMessage(req.GasCap, cfg.BaseFee)
args.Gas = (*hexutil.Uint64)(&gas) if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) // NOTE: the errors from the executable below should be consistent with go-ethereum,
if err != nil { // so we don't wrap them with the gRPC status code
return false, nil, err
} // 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 // pass false to not commit StateDB
rsp, err = k.ApplyMessageWithConfig(ctx, msg, nil, false, cfg, txConfig) 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 // Execute the binary search and hone in on an executable gas limit
hi, err = types.BinSearch(lo, hi, executable) hi, err = types.BinSearch(lo, hi, executable)
if err != nil { 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 // Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap { if hi == cap {
failed, result, err := executable(hi) failed, result, err := executable(hi)
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
if failed { if failed {
if result != nil && result.VmError != vm.ErrOutOfGas.Error() { if result != nil && result.VmError != vm.ErrOutOfGas.Error() {
if result.VmError == vm.ErrExecutionReverted.Error() { if result.VmError == vm.ErrExecutionReverted.Error() {
return nil, types.NewExecErrorWithReason(result.Ret) 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 // 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 return &types.EstimateGasResponse{Gas: hi}, nil