rpc, evm: use binary search to estimate gas (#272)

* do binary search to estimate gas

Closes #268

- Also refactor ApplyMessage to be more reuseable

move binary search to rpc api side to have a clean context each try

remove EstimateGas grpc api

* extract BinSearch function and add unit test

* do estimateGas in grpc query

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang
2021-07-19 15:19:23 +00:00
committed by GitHub
co-authored by Federico Kunze Küllmer
parent 072f0534db
commit 14b38af8bc
14 changed files with 831 additions and 85 deletions
+27 -6
View File
@@ -550,11 +550,21 @@ func (e *PublicAPI) doCall(
if err != nil {
return nil, err
}
req := evmtypes.EthCallRequest{Args: bz}
req := evmtypes.EthCallRequest{Args: bz, GasCap: ethermint.DefaultRPCGasLimit}
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
// the latest block height for querying.
res, err := e.queryClient.EthCall(rpctypes.ContextWithHeight(blockNr.Int64()), &req)
if err != nil {
return nil, err
}
if len(res.VmError) > 0 {
if res.VmError == vm.ErrExecutionReverted.Error() {
return nil, evmtypes.NewExecErrorWithReason(res.Ret)
}
return nil, errors.New(res.VmError)
}
if res.Failed() {
if res.VmError == vm.ErrExecutionReverted.Error() {
@@ -567,18 +577,28 @@ func (e *PublicAPI) doCall(
}
// EstimateGas returns an estimate of gas usage for the given smart contract call.
func (e *PublicAPI) EstimateGas(args evmtypes.CallArgs) (hexutil.Uint64, error) {
func (e *PublicAPI) EstimateGas(args evmtypes.CallArgs, blockNrOptional *rpctypes.BlockNumber) (hexutil.Uint64, error) {
e.logger.Debug("eth_estimateGas")
blockNr := rpctypes.EthPendingBlockNumber
if blockNrOptional != nil {
blockNr = *blockNrOptional
}
bz, err := json.Marshal(&args)
if err != nil {
return 0, err
}
req := evmtypes.EthCallRequest{Args: bz, GasCap: ethermint.DefaultRPCGasLimit}
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
// the latest block height for querying.
data, err := e.doCall(args, 0)
res, err := e.queryClient.EstimateGas(rpctypes.ContextWithHeight(blockNr.Int64()), &req)
if err != nil {
return 0, err
}
return hexutil.Uint64(data.GasUsed), nil
return hexutil.Uint64(res.Gas), nil
}
// GetBlockByHash returns the block identified by hash.
@@ -1027,7 +1047,8 @@ func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs
Data: input,
AccessList: args.AccessList,
}
estimated, err := e.EstimateGas(callArgs)
blockNr := rpctypes.NewBlockNumber(big.NewInt(0))
estimated, err := e.EstimateGas(callArgs, &blockNr)
if err != nil {
return args, err
}