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:
parent
072f0534db
commit
14b38af8bc
@ -68,6 +68,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
* (rpc) [#124](https://github.com/tharsis/ethermint/issues/124) Implement `txpool_content`, `txpool_inspect` and `txpool_status` RPC methods
|
* (rpc) [#124](https://github.com/tharsis/ethermint/issues/124) Implement `txpool_content`, `txpool_inspect` and `txpool_status` RPC methods
|
||||||
* (rpc) [tharsis#112](https://github.com/tharsis/ethermint/pull/153) Fix `eth_coinbase` to return the ethereum address of the validator
|
* (rpc) [tharsis#112](https://github.com/tharsis/ethermint/pull/153) Fix `eth_coinbase` to return the ethereum address of the validator
|
||||||
* (rpc) [tharsis#176](https://github.com/tharsis/ethermint/issues/176) Support fetching pending nonce
|
* (rpc) [tharsis#176](https://github.com/tharsis/ethermint/issues/176) Support fetching pending nonce
|
||||||
|
* (rpc) [tharsis#272](https://github.com/tharsis/ethermint/pull/272) do binary search to estimate gas accurately
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1433,6 +1433,225 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
tags:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
|
/ethermint/evm/v1alpha1/estimate_gas:
|
||||||
|
get:
|
||||||
|
summary: EstimateGas implements the `eth_estimateGas` rpc api
|
||||||
|
operationId: EstimateGas
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A successful response.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
gas:
|
||||||
|
type: string
|
||||||
|
format: uint64
|
||||||
|
title: the estimated gas
|
||||||
|
title: EstimateGasResponse defines EstimateGas response
|
||||||
|
default:
|
||||||
|
description: An unexpected error response
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
details:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
type_url:
|
||||||
|
type: string
|
||||||
|
description: >-
|
||||||
|
A URL/resource name that uniquely identifies the type of
|
||||||
|
the serialized
|
||||||
|
|
||||||
|
protocol buffer message. This string must contain at
|
||||||
|
least
|
||||||
|
|
||||||
|
one "/" character. The last segment of the URL's path
|
||||||
|
must represent
|
||||||
|
|
||||||
|
the fully qualified name of the type (as in
|
||||||
|
|
||||||
|
`path/google.protobuf.Duration`). The name should be in
|
||||||
|
a canonical form
|
||||||
|
|
||||||
|
(e.g., leading "." is not accepted).
|
||||||
|
|
||||||
|
|
||||||
|
In practice, teams usually precompile into the binary
|
||||||
|
all types that they
|
||||||
|
|
||||||
|
expect it to use in the context of Any. However, for
|
||||||
|
URLs which use the
|
||||||
|
|
||||||
|
scheme `http`, `https`, or no scheme, one can optionally
|
||||||
|
set up a type
|
||||||
|
|
||||||
|
server that maps type URLs to message definitions as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
|
||||||
|
* If no scheme is provided, `https` is assumed.
|
||||||
|
|
||||||
|
* An HTTP GET on the URL must yield a
|
||||||
|
[google.protobuf.Type][]
|
||||||
|
value in binary format, or produce an error.
|
||||||
|
* Applications are allowed to cache lookup results based
|
||||||
|
on the
|
||||||
|
URL, or have them precompiled into a binary to avoid any
|
||||||
|
lookup. Therefore, binary compatibility needs to be preserved
|
||||||
|
on changes to types. (Use versioned type names to manage
|
||||||
|
breaking changes.)
|
||||||
|
|
||||||
|
Note: this functionality is not currently available in
|
||||||
|
the official
|
||||||
|
|
||||||
|
protobuf release, and it is not used for type URLs
|
||||||
|
beginning with
|
||||||
|
|
||||||
|
type.googleapis.com.
|
||||||
|
|
||||||
|
|
||||||
|
Schemes other than `http`, `https` (or the empty scheme)
|
||||||
|
might be
|
||||||
|
|
||||||
|
used with implementation specific semantics.
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
format: byte
|
||||||
|
description: >-
|
||||||
|
Must be a valid serialized protocol buffer of the above
|
||||||
|
specified type.
|
||||||
|
description: >-
|
||||||
|
`Any` contains an arbitrary serialized protocol buffer
|
||||||
|
message along with a
|
||||||
|
|
||||||
|
URL that describes the type of the serialized message.
|
||||||
|
|
||||||
|
|
||||||
|
Protobuf library provides support to pack/unpack Any values
|
||||||
|
in the form
|
||||||
|
|
||||||
|
of utility functions or additional generated methods of the
|
||||||
|
Any type.
|
||||||
|
|
||||||
|
|
||||||
|
Example 1: Pack and unpack a message in C++.
|
||||||
|
|
||||||
|
Foo foo = ...;
|
||||||
|
Any any;
|
||||||
|
any.PackFrom(foo);
|
||||||
|
...
|
||||||
|
if (any.UnpackTo(&foo)) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Example 2: Pack and unpack a message in Java.
|
||||||
|
|
||||||
|
Foo foo = ...;
|
||||||
|
Any any = Any.pack(foo);
|
||||||
|
...
|
||||||
|
if (any.is(Foo.class)) {
|
||||||
|
foo = any.unpack(Foo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
Example 3: Pack and unpack a message in Python.
|
||||||
|
|
||||||
|
foo = Foo(...)
|
||||||
|
any = Any()
|
||||||
|
any.Pack(foo)
|
||||||
|
...
|
||||||
|
if any.Is(Foo.DESCRIPTOR):
|
||||||
|
any.Unpack(foo)
|
||||||
|
...
|
||||||
|
|
||||||
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
|
foo := &pb.Foo{...}
|
||||||
|
any, err := ptypes.MarshalAny(foo)
|
||||||
|
...
|
||||||
|
foo := &pb.Foo{}
|
||||||
|
if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
The pack methods provided by protobuf library will by
|
||||||
|
default use
|
||||||
|
|
||||||
|
'type.googleapis.com/full.type.name' as the type URL and the
|
||||||
|
unpack
|
||||||
|
|
||||||
|
methods only use the fully qualified type name after the
|
||||||
|
last '/'
|
||||||
|
|
||||||
|
in the type URL, for example "foo.bar.com/x/y.z" will yield
|
||||||
|
type
|
||||||
|
|
||||||
|
name "y.z".
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
JSON
|
||||||
|
|
||||||
|
====
|
||||||
|
|
||||||
|
The JSON representation of an `Any` value uses the regular
|
||||||
|
|
||||||
|
representation of the deserialized, embedded message, with
|
||||||
|
an
|
||||||
|
|
||||||
|
additional field `@type` which contains the type URL.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
package google.profile;
|
||||||
|
message Person {
|
||||||
|
string first_name = 1;
|
||||||
|
string last_name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/google.profile.Person",
|
||||||
|
"firstName": <string>,
|
||||||
|
"lastName": <string>
|
||||||
|
}
|
||||||
|
|
||||||
|
If the embedded message type is well-known and has a custom
|
||||||
|
JSON
|
||||||
|
|
||||||
|
representation, that representation will be embedded adding
|
||||||
|
a field
|
||||||
|
|
||||||
|
`value` which holds the custom JSON in addition to the
|
||||||
|
`@type`
|
||||||
|
|
||||||
|
field. Example (for message [google.protobuf.Duration][]):
|
||||||
|
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/google.protobuf.Duration",
|
||||||
|
"value": "1.212s"
|
||||||
|
}
|
||||||
|
parameters:
|
||||||
|
- name: args
|
||||||
|
description: same json format as the json rpc api.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: byte
|
||||||
|
- name: gas_cap
|
||||||
|
description: the default gas cap to be used.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: uint64
|
||||||
|
tags:
|
||||||
|
- Query
|
||||||
/ethermint/evm/v1alpha1/eth_call:
|
/ethermint/evm/v1alpha1/eth_call:
|
||||||
get:
|
get:
|
||||||
summary: EthCall implements the `eth_call` rpc api
|
summary: EthCall implements the `eth_call` rpc api
|
||||||
@ -1721,6 +1940,12 @@ paths:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
format: byte
|
format: byte
|
||||||
|
- name: gas_cap
|
||||||
|
description: the default gas cap to be used.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: uint64
|
||||||
tags:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
/ethermint/evm/v1alpha1/params:
|
/ethermint/evm/v1alpha1/params:
|
||||||
@ -12878,6 +13103,14 @@ definitions:
|
|||||||
values
|
values
|
||||||
|
|
||||||
instead of *big.Int.
|
instead of *big.Int.
|
||||||
|
ethermint.evm.v1alpha1.EstimateGasResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
gas:
|
||||||
|
type: string
|
||||||
|
format: uint64
|
||||||
|
title: the estimated gas
|
||||||
|
title: EstimateGasResponse defines EstimateGas response
|
||||||
ethermint.evm.v1alpha1.Log:
|
ethermint.evm.v1alpha1.Log:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
- [Msg](#ethermint.evm.v1alpha1.Msg)
|
- [Msg](#ethermint.evm.v1alpha1.Msg)
|
||||||
|
|
||||||
- [ethermint/evm/v1alpha1/query.proto](#ethermint/evm/v1alpha1/query.proto)
|
- [ethermint/evm/v1alpha1/query.proto](#ethermint/evm/v1alpha1/query.proto)
|
||||||
|
- [EstimateGasResponse](#ethermint.evm.v1alpha1.EstimateGasResponse)
|
||||||
- [EthCallRequest](#ethermint.evm.v1alpha1.EthCallRequest)
|
- [EthCallRequest](#ethermint.evm.v1alpha1.EthCallRequest)
|
||||||
- [QueryAccountRequest](#ethermint.evm.v1alpha1.QueryAccountRequest)
|
- [QueryAccountRequest](#ethermint.evm.v1alpha1.QueryAccountRequest)
|
||||||
- [QueryAccountResponse](#ethermint.evm.v1alpha1.QueryAccountResponse)
|
- [QueryAccountResponse](#ethermint.evm.v1alpha1.QueryAccountResponse)
|
||||||
@ -467,6 +468,21 @@ Msg defines the evm Msg service.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="ethermint.evm.v1alpha1.EstimateGasResponse"></a>
|
||||||
|
|
||||||
|
### EstimateGasResponse
|
||||||
|
EstimateGasResponse defines EstimateGas response
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| `gas` | [uint64](#uint64) | | the estimated gas |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="ethermint.evm.v1alpha1.EthCallRequest"></a>
|
<a name="ethermint.evm.v1alpha1.EthCallRequest"></a>
|
||||||
|
|
||||||
### EthCallRequest
|
### EthCallRequest
|
||||||
@ -476,6 +492,7 @@ EthCallRequest defines EthCall request
|
|||||||
| Field | Type | Label | Description |
|
| Field | Type | Label | Description |
|
||||||
| ----- | ---- | ----- | ----------- |
|
| ----- | ---- | ----- | ----------- |
|
||||||
| `args` | [bytes](#bytes) | | same json format as the json rpc api. |
|
| `args` | [bytes](#bytes) | | same json format as the json rpc api. |
|
||||||
|
| `gas_cap` | [uint64](#uint64) | | the default gas cap to be used |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -841,6 +858,7 @@ Query defines the gRPC querier service.
|
|||||||
| `Params` | [QueryParamsRequest](#ethermint.evm.v1alpha1.QueryParamsRequest) | [QueryParamsResponse](#ethermint.evm.v1alpha1.QueryParamsResponse) | Params queries the parameters of x/evm module. | GET|/ethermint/evm/v1alpha1/params|
|
| `Params` | [QueryParamsRequest](#ethermint.evm.v1alpha1.QueryParamsRequest) | [QueryParamsResponse](#ethermint.evm.v1alpha1.QueryParamsResponse) | Params queries the parameters of x/evm module. | GET|/ethermint/evm/v1alpha1/params|
|
||||||
| `StaticCall` | [QueryStaticCallRequest](#ethermint.evm.v1alpha1.QueryStaticCallRequest) | [QueryStaticCallResponse](#ethermint.evm.v1alpha1.QueryStaticCallResponse) | StaticCall queries the static call value of x/evm module. | GET|/ethermint/evm/v1alpha1/static_call|
|
| `StaticCall` | [QueryStaticCallRequest](#ethermint.evm.v1alpha1.QueryStaticCallRequest) | [QueryStaticCallResponse](#ethermint.evm.v1alpha1.QueryStaticCallResponse) | StaticCall queries the static call value of x/evm module. | GET|/ethermint/evm/v1alpha1/static_call|
|
||||||
| `EthCall` | [EthCallRequest](#ethermint.evm.v1alpha1.EthCallRequest) | [MsgEthereumTxResponse](#ethermint.evm.v1alpha1.MsgEthereumTxResponse) | EthCall implements the `eth_call` rpc api | GET|/ethermint/evm/v1alpha1/eth_call|
|
| `EthCall` | [EthCallRequest](#ethermint.evm.v1alpha1.EthCallRequest) | [MsgEthereumTxResponse](#ethermint.evm.v1alpha1.MsgEthereumTxResponse) | EthCall implements the `eth_call` rpc api | GET|/ethermint/evm/v1alpha1/eth_call|
|
||||||
|
| `EstimateGas` | [EthCallRequest](#ethermint.evm.v1alpha1.EthCallRequest) | [EstimateGasResponse](#ethermint.evm.v1alpha1.EstimateGasResponse) | EstimateGas implements the `eth_estimateGas` rpc api | GET|/ethermint/evm/v1alpha1/estimate_gas|
|
||||||
|
|
||||||
<!-- end services -->
|
<!-- end services -->
|
||||||
|
|
||||||
|
@ -550,11 +550,21 @@ func (e *PublicAPI) doCall(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
res, err := e.queryClient.EthCall(rpctypes.ContextWithHeight(blockNr.Int64()), &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.Failed() {
|
||||||
if res.VmError == vm.ErrExecutionReverted.Error() {
|
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.
|
// 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")
|
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,
|
// From ContextWithHeight: if the provided height is 0,
|
||||||
// it will return an empty context and the gRPC query will use
|
// it will return an empty context and the gRPC query will use
|
||||||
// the latest block height for querying.
|
// 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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
return hexutil.Uint64(res.Gas), nil
|
||||||
return hexutil.Uint64(data.GasUsed), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByHash returns the block identified by hash.
|
// GetBlockByHash returns the block identified by hash.
|
||||||
@ -1027,7 +1047,8 @@ func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs
|
|||||||
Data: input,
|
Data: input,
|
||||||
AccessList: args.AccessList,
|
AccessList: args.AccessList,
|
||||||
}
|
}
|
||||||
estimated, err := e.EstimateGas(callArgs)
|
blockNr := rpctypes.NewBlockNumber(big.NewInt(0))
|
||||||
|
estimated, err := e.EstimateGas(callArgs, &blockNr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return args, err
|
return args, err
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,12 @@ service Query {
|
|||||||
rpc EthCall(EthCallRequest) returns (MsgEthereumTxResponse) {
|
rpc EthCall(EthCallRequest) returns (MsgEthereumTxResponse) {
|
||||||
option (google.api.http).get = "/ethermint/evm/v1alpha1/eth_call";
|
option (google.api.http).get = "/ethermint/evm/v1alpha1/eth_call";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EstimateGas implements the `eth_estimateGas` rpc api
|
||||||
|
rpc EstimateGas(EthCallRequest) returns (EstimateGasResponse) {
|
||||||
|
option (google.api.http).get = "/ethermint/evm/v1alpha1/estimate_gas";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryAccountRequest is the request type for the Query/Account RPC method.
|
// QueryAccountRequest is the request type for the Query/Account RPC method.
|
||||||
@ -251,4 +257,12 @@ message QueryStaticCallResponse {
|
|||||||
message EthCallRequest {
|
message EthCallRequest {
|
||||||
// same json format as the json rpc api.
|
// same json format as the json rpc api.
|
||||||
bytes args = 1;
|
bytes args = 1;
|
||||||
|
// the default gas cap to be used
|
||||||
|
uint64 gas_cap = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateGasResponse defines EstimateGas response
|
||||||
|
message EstimateGasResponse {
|
||||||
|
// the estimated gas
|
||||||
|
uint64 gas = 1;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
|||||||
if config.EVMRPC.Enable {
|
if config.EVMRPC.Enable {
|
||||||
tmEndpoint := "/websocket"
|
tmEndpoint := "/websocket"
|
||||||
tmRPCAddr := cfg.RPC.ListenAddress
|
tmRPCAddr := cfg.RPC.ListenAddress
|
||||||
logger.Info("EVM RPC Connecting to Tendermint WebSocket at", tmRPCAddr+tmEndpoint)
|
logger.Info("EVM RPC Connecting to Tendermint WebSocket at", "address", tmRPCAddr+tmEndpoint)
|
||||||
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint)
|
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint)
|
||||||
|
|
||||||
rpcServer := ethrpc.NewServer()
|
rpcServer := ethrpc.NewServer()
|
||||||
|
@ -803,9 +803,10 @@ func TestEth_EstimateGas(t *testing.T) {
|
|||||||
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
||||||
param[0]["to"] = "0x1122334455667788990011223344556677889900"
|
param[0]["to"] = "0x1122334455667788990011223344556677889900"
|
||||||
param[0]["value"] = "0x1"
|
param[0]["value"] = "0x1"
|
||||||
|
param[0]["gas"] = "0x5209"
|
||||||
rpcRes := call(t, "eth_estimateGas", param)
|
rpcRes := call(t, "eth_estimateGas", param)
|
||||||
require.NotNil(t, rpcRes)
|
require.NotNil(t, rpcRes)
|
||||||
require.NotEmpty(t, rpcRes.Result)
|
require.Equal(t, rpcRes.Result, "0x5208")
|
||||||
|
|
||||||
var gas string
|
var gas string
|
||||||
err := json.Unmarshal(rpcRes.Result, &gas)
|
err := json.Unmarshal(rpcRes.Result, &gas)
|
||||||
|
@ -3,7 +3,10 @@ package keeper
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/palantir/stacktrace"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
@ -13,7 +16,11 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/types/query"
|
"github.com/cosmos/cosmos-sdk/types/query"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
ethparams "github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
ethermint "github.com/tharsis/ethermint/types"
|
ethermint "github.com/tharsis/ethermint/types"
|
||||||
"github.com/tharsis/ethermint/x/evm/types"
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
@ -374,7 +381,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms
|
|||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := args.ToMessage(uint64(ethermint.DefaultRPCGasLimit))
|
msg := args.ToMessage(req.GasCap)
|
||||||
|
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
|
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
|
||||||
@ -393,3 +400,100 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms
|
|||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EstimateGas implements eth_estimateGas rpc api.
|
||||||
|
func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*types.EstimateGasResponse, error) {
|
||||||
|
ctx := sdk.UnwrapSDKContext(c)
|
||||||
|
k.WithContext(ctx)
|
||||||
|
|
||||||
|
var args types.CallArgs
|
||||||
|
err := json.Unmarshal(req.Args, &args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary search the gas requirement, as it may be higher than the amount used
|
||||||
|
var (
|
||||||
|
lo uint64 = ethparams.TxGas - 1
|
||||||
|
hi uint64
|
||||||
|
cap uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
// Determine the highest gas limit can be used during the estimation.
|
||||||
|
if args.Gas != nil && uint64(*args.Gas) >= ethparams.TxGas {
|
||||||
|
hi = uint64(*args.Gas)
|
||||||
|
} else {
|
||||||
|
// Query block gas limit
|
||||||
|
params := ctx.ConsensusParams()
|
||||||
|
if params != nil && params.Block != nil && params.Block.MaxGas > 0 {
|
||||||
|
hi = uint64(params.Block.MaxGas)
|
||||||
|
} else {
|
||||||
|
hi = req.GasCap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Recap the highest gas limit with account's available balance.
|
||||||
|
|
||||||
|
// Recap the highest gas allowance with specified gascap.
|
||||||
|
if req.GasCap != 0 && hi > req.GasCap {
|
||||||
|
hi = req.GasCap
|
||||||
|
}
|
||||||
|
cap = hi
|
||||||
|
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
|
||||||
|
|
||||||
|
coinbase, err := k.GetCoinbaseAddress()
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a helper to check if a gas allowance results in an executable transaction
|
||||||
|
executable := func(gas uint64) (bool, *types.MsgEthereumTxResponse, error) {
|
||||||
|
args.Gas = (*hexutil.Uint64)(&gas)
|
||||||
|
|
||||||
|
// Execute the call in an isolated context
|
||||||
|
sandboxCtx, _ := ctx.CacheContext()
|
||||||
|
k.WithContext(sandboxCtx)
|
||||||
|
|
||||||
|
msg := args.ToMessage(req.GasCap)
|
||||||
|
evm := k.NewEVM(msg, ethCfg, params, coinbase)
|
||||||
|
// pass true means execute in query mode, which don't do actual gas refund.
|
||||||
|
rsp, err := k.ApplyMessage(evm, msg, ethCfg, true)
|
||||||
|
|
||||||
|
k.WithContext(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(stacktrace.RootCause(err), core.ErrIntrinsicGas) {
|
||||||
|
return true, nil, nil // Special case, raise gas limit
|
||||||
|
}
|
||||||
|
return true, nil, err // Bail out
|
||||||
|
}
|
||||||
|
return len(rsp.VmError) > 0, rsp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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())
|
||||||
|
}
|
||||||
|
if failed {
|
||||||
|
if result != nil && result.VmError != vm.ErrOutOfGas.Error() {
|
||||||
|
if result.VmError == vm.ErrExecutionReverted.Error() {
|
||||||
|
return nil, status.Error(codes.Internal, types.NewExecErrorWithReason(result.Ret).Error())
|
||||||
|
}
|
||||||
|
return nil, status.Error(codes.Internal, 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 &types.EstimateGasResponse{Gas: hi}, nil
|
||||||
|
}
|
||||||
|
@ -246,7 +246,7 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo
|
|||||||
// Should check again even if it is checked on Ante Handler, because eth_call don't go through Ante Handler.
|
// Should check again even if it is checked on Ante Handler, because eth_call don't go through Ante Handler.
|
||||||
if msg.Gas() < intrinsicGas {
|
if msg.Gas() < intrinsicGas {
|
||||||
// eth_estimateGas will check for this exact error
|
// eth_estimateGas will check for this exact error
|
||||||
return nil, stacktrace.Propagate(core.ErrIntrinsicGas, "intrinsic gas too low")
|
return nil, stacktrace.Propagate(core.ErrIntrinsicGas, "apply message")
|
||||||
}
|
}
|
||||||
leftoverGas := msg.Gas() - intrinsicGas
|
leftoverGas := msg.Gas() - intrinsicGas
|
||||||
|
|
||||||
|
@ -1051,6 +1051,8 @@ func (m *QueryStaticCallResponse) GetData() []byte {
|
|||||||
type EthCallRequest struct {
|
type EthCallRequest struct {
|
||||||
// same json format as the json rpc api.
|
// same json format as the json rpc api.
|
||||||
Args []byte `protobuf:"bytes,1,opt,name=args,proto3" json:"args,omitempty"`
|
Args []byte `protobuf:"bytes,1,opt,name=args,proto3" json:"args,omitempty"`
|
||||||
|
// the default gas cap to be used
|
||||||
|
GasCap uint64 `protobuf:"varint,2,opt,name=gas_cap,json=gasCap,proto3" json:"gas_cap,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *EthCallRequest) Reset() { *m = EthCallRequest{} }
|
func (m *EthCallRequest) Reset() { *m = EthCallRequest{} }
|
||||||
@ -1093,6 +1095,59 @@ func (m *EthCallRequest) GetArgs() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *EthCallRequest) GetGasCap() uint64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.GasCap
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateGasResponse defines EstimateGas response
|
||||||
|
type EstimateGasResponse struct {
|
||||||
|
// the estimated gas
|
||||||
|
Gas uint64 `protobuf:"varint,1,opt,name=gas,proto3" json:"gas,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EstimateGasResponse) Reset() { *m = EstimateGasResponse{} }
|
||||||
|
func (m *EstimateGasResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*EstimateGasResponse) ProtoMessage() {}
|
||||||
|
func (*EstimateGasResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_8bbc79ec2b6c5cb2, []int{23}
|
||||||
|
}
|
||||||
|
func (m *EstimateGasResponse) XXX_Unmarshal(b []byte) error {
|
||||||
|
return m.Unmarshal(b)
|
||||||
|
}
|
||||||
|
func (m *EstimateGasResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
if deterministic {
|
||||||
|
return xxx_messageInfo_EstimateGasResponse.Marshal(b, m, deterministic)
|
||||||
|
} else {
|
||||||
|
b = b[:cap(b)]
|
||||||
|
n, err := m.MarshalToSizedBuffer(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b[:n], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (m *EstimateGasResponse) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_EstimateGasResponse.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *EstimateGasResponse) XXX_Size() int {
|
||||||
|
return m.Size()
|
||||||
|
}
|
||||||
|
func (m *EstimateGasResponse) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_EstimateGasResponse.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_EstimateGasResponse proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *EstimateGasResponse) GetGas() uint64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Gas
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterType((*QueryAccountRequest)(nil), "ethermint.evm.v1alpha1.QueryAccountRequest")
|
proto.RegisterType((*QueryAccountRequest)(nil), "ethermint.evm.v1alpha1.QueryAccountRequest")
|
||||||
proto.RegisterType((*QueryAccountResponse)(nil), "ethermint.evm.v1alpha1.QueryAccountResponse")
|
proto.RegisterType((*QueryAccountResponse)(nil), "ethermint.evm.v1alpha1.QueryAccountResponse")
|
||||||
@ -1117,6 +1172,7 @@ func init() {
|
|||||||
proto.RegisterType((*QueryStaticCallRequest)(nil), "ethermint.evm.v1alpha1.QueryStaticCallRequest")
|
proto.RegisterType((*QueryStaticCallRequest)(nil), "ethermint.evm.v1alpha1.QueryStaticCallRequest")
|
||||||
proto.RegisterType((*QueryStaticCallResponse)(nil), "ethermint.evm.v1alpha1.QueryStaticCallResponse")
|
proto.RegisterType((*QueryStaticCallResponse)(nil), "ethermint.evm.v1alpha1.QueryStaticCallResponse")
|
||||||
proto.RegisterType((*EthCallRequest)(nil), "ethermint.evm.v1alpha1.EthCallRequest")
|
proto.RegisterType((*EthCallRequest)(nil), "ethermint.evm.v1alpha1.EthCallRequest")
|
||||||
|
proto.RegisterType((*EstimateGasResponse)(nil), "ethermint.evm.v1alpha1.EstimateGasResponse")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -1124,81 +1180,85 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptor_8bbc79ec2b6c5cb2 = []byte{
|
var fileDescriptor_8bbc79ec2b6c5cb2 = []byte{
|
||||||
// 1179 bytes of a gzipped FileDescriptorProto
|
// 1245 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x97, 0x4d, 0x6f, 0x1b, 0x45,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x97, 0x4d, 0x6f, 0x1b, 0x45,
|
||||||
0x18, 0xc7, 0xbd, 0x89, 0x13, 0x27, 0x4f, 0x5e, 0x08, 0x83, 0x29, 0x61, 0x5b, 0x9c, 0x30, 0xd0,
|
0x18, 0xc7, 0xbd, 0x8d, 0x63, 0x37, 0x4f, 0x92, 0x36, 0x4c, 0x4d, 0x1b, 0xb6, 0xc5, 0x09, 0x03,
|
||||||
0xc4, 0x79, 0xe9, 0x6e, 0x6d, 0xde, 0x4a, 0x85, 0x04, 0x49, 0xd5, 0x50, 0xa9, 0x05, 0x15, 0x27,
|
0x8d, 0x9d, 0x97, 0xee, 0xd6, 0xe6, 0xad, 0x54, 0x20, 0x48, 0xa2, 0xa4, 0x95, 0x5a, 0x50, 0x71,
|
||||||
0xe2, 0xc0, 0x25, 0x1a, 0xaf, 0x57, 0x6b, 0x2b, 0xf6, 0x8e, 0xbb, 0x33, 0xb6, 0x12, 0x45, 0xb9,
|
0x22, 0x0e, 0x5c, 0xac, 0xf1, 0x7a, 0xb5, 0xb6, 0x62, 0xef, 0xb8, 0x3b, 0x6b, 0x2b, 0x51, 0x94,
|
||||||
0x70, 0x40, 0xbc, 0x1d, 0x40, 0x1c, 0x40, 0x48, 0x48, 0xbd, 0x72, 0xe3, 0x2b, 0x70, 0xeb, 0xb1,
|
0x0b, 0x07, 0xc4, 0xdb, 0xa1, 0x88, 0x03, 0x08, 0x09, 0xa9, 0x57, 0x6e, 0x7c, 0x05, 0x6e, 0x3d,
|
||||||
0x12, 0x17, 0x4e, 0x08, 0x25, 0x1c, 0xe0, 0x5b, 0xa0, 0x79, 0x59, 0x7b, 0xd7, 0xc9, 0x7a, 0x1d,
|
0x56, 0xe2, 0xc2, 0x09, 0xa1, 0x84, 0x03, 0x1f, 0x82, 0x03, 0x9a, 0x97, 0xb5, 0x77, 0x1d, 0x6f,
|
||||||
0xc4, 0x6d, 0x66, 0xf6, 0x79, 0xf9, 0x3d, 0xcf, 0x3c, 0x9e, 0x7f, 0x02, 0xd8, 0xe5, 0x75, 0x37,
|
0xd6, 0x41, 0xdc, 0x66, 0x66, 0x9f, 0x97, 0xdf, 0xf3, 0xcc, 0xe3, 0xf9, 0x27, 0x80, 0x6d, 0xbf,
|
||||||
0x68, 0x35, 0x7c, 0x6e, 0xbb, 0xdd, 0x96, 0xdd, 0x2d, 0x91, 0x66, 0xbb, 0x4e, 0x4a, 0xf6, 0xa3,
|
0x61, 0x7b, 0xed, 0xa6, 0xeb, 0x9b, 0x76, 0xaf, 0x6d, 0xf6, 0x4a, 0xa4, 0xd5, 0x69, 0x90, 0x92,
|
||||||
0x8e, 0x1b, 0x1c, 0x59, 0xed, 0x80, 0x72, 0x8a, 0xae, 0xf4, 0x6c, 0x2c, 0xb7, 0xdb, 0xb2, 0x42,
|
0xf9, 0xb8, 0x6b, 0x7b, 0x07, 0x46, 0xc7, 0xa3, 0x3e, 0x45, 0x57, 0xfb, 0x36, 0x86, 0xdd, 0x6b,
|
||||||
0x1b, 0x33, 0xef, 0x51, 0x8f, 0x4a, 0x13, 0x5b, 0xac, 0x94, 0xb5, 0xb9, 0xee, 0x50, 0xd6, 0xa2,
|
0x1b, 0x81, 0x8d, 0x9e, 0x73, 0xa8, 0x43, 0x85, 0x89, 0xc9, 0x57, 0xd2, 0x5a, 0x5f, 0xb1, 0x28,
|
||||||
0xcc, 0xae, 0x12, 0xe6, 0xaa, 0x30, 0x76, 0xb7, 0x54, 0x75, 0x39, 0x29, 0xd9, 0x6d, 0xe2, 0x35,
|
0x6b, 0x53, 0x66, 0xd6, 0x08, 0xb3, 0x65, 0x18, 0xb3, 0x57, 0xaa, 0xd9, 0x3e, 0x29, 0x99, 0x1d,
|
||||||
0x7c, 0xc2, 0x1b, 0xd4, 0xd7, 0xb6, 0xd7, 0x3c, 0x4a, 0xbd, 0xa6, 0x6b, 0x93, 0x76, 0xc3, 0x26,
|
0xe2, 0x34, 0x5d, 0xe2, 0x37, 0xa9, 0xab, 0x6c, 0x6f, 0x38, 0x94, 0x3a, 0x2d, 0xdb, 0x24, 0x9d,
|
||||||
0xbe, 0x4f, 0xb9, 0xfc, 0xc8, 0xf4, 0xd7, 0xe5, 0x04, 0x36, 0x01, 0xa1, 0x2c, 0x96, 0x12, 0x2c,
|
0xa6, 0x49, 0x5c, 0x97, 0xfa, 0xe2, 0x23, 0x53, 0x5f, 0x17, 0x63, 0xd8, 0x38, 0x84, 0xb4, 0x58,
|
||||||
0xf8, 0xa1, 0x32, 0xc0, 0x6f, 0xc3, 0x73, 0x1f, 0x09, 0x84, 0x2d, 0xc7, 0xa1, 0x1d, 0x9f, 0x57,
|
0x88, 0xb1, 0xf0, 0xf7, 0xa5, 0x01, 0x7e, 0x07, 0xae, 0x7c, 0xcc, 0x11, 0xd6, 0x2d, 0x8b, 0x76,
|
||||||
0xdc, 0x47, 0x1d, 0x97, 0x71, 0xb4, 0x08, 0x39, 0x52, 0xab, 0x05, 0x2e, 0x63, 0x8b, 0xc6, 0xb2,
|
0x5d, 0xbf, 0x62, 0x3f, 0xee, 0xda, 0xcc, 0x47, 0xf3, 0x90, 0x25, 0xf5, 0xba, 0x67, 0x33, 0x36,
|
||||||
0x51, 0x9c, 0xae, 0x84, 0xdb, 0xdb, 0x53, 0x9f, 0x3f, 0x5e, 0xca, 0xfc, 0xfd, 0x78, 0x29, 0x83,
|
0xaf, 0x2d, 0x6a, 0xc5, 0xa9, 0x4a, 0xb0, 0xbd, 0x7b, 0xf1, 0x8b, 0xa7, 0x0b, 0xa9, 0xbf, 0x9f,
|
||||||
0x1d, 0xc8, 0xc7, 0x5d, 0x59, 0x9b, 0xfa, 0xcc, 0x15, 0xbe, 0x55, 0xd2, 0x24, 0xbe, 0xe3, 0x86,
|
0x2e, 0xa4, 0xb0, 0x05, 0xb9, 0xa8, 0x2b, 0xeb, 0x50, 0x97, 0xd9, 0xdc, 0xb7, 0x46, 0x5a, 0xc4,
|
||||||
0xbe, 0x7a, 0x8b, 0xae, 0xc2, 0xb4, 0x43, 0x6b, 0xee, 0x7e, 0x9d, 0xb0, 0xfa, 0xe2, 0x98, 0xfc,
|
0xb5, 0xec, 0xc0, 0x57, 0x6d, 0xd1, 0x75, 0x98, 0xb2, 0x68, 0xdd, 0xae, 0x36, 0x08, 0x6b, 0xcc,
|
||||||
0x36, 0x25, 0x0e, 0xee, 0x11, 0x56, 0x47, 0x79, 0x98, 0xf0, 0xa9, 0x70, 0x1a, 0x5f, 0x36, 0x8a,
|
0x5f, 0x10, 0xdf, 0x2e, 0xf2, 0x83, 0xfb, 0x84, 0x35, 0x50, 0x0e, 0x26, 0x5d, 0xca, 0x9d, 0x26,
|
||||||
0xd9, 0x8a, 0xda, 0xe0, 0x77, 0xe1, 0x45, 0x99, 0xe4, 0x8e, 0xec, 0xd9, 0x7f, 0xa0, 0xfc, 0xcc,
|
0x16, 0xb5, 0x62, 0xba, 0x22, 0x37, 0xf8, 0x7d, 0x78, 0x49, 0x24, 0xd9, 0x14, 0x3d, 0xfb, 0x0f,
|
||||||
0x00, 0xf3, 0xa2, 0x08, 0x1a, 0xf6, 0x3a, 0xcc, 0xab, 0xeb, 0xd8, 0x8f, 0x47, 0x9a, 0x53, 0xa7,
|
0x94, 0x9f, 0x6b, 0xa0, 0x8f, 0x8a, 0xa0, 0x60, 0x6f, 0xc2, 0x25, 0x79, 0x1d, 0xd5, 0x68, 0xa4,
|
||||||
0x5b, 0xea, 0x10, 0x99, 0x30, 0xc5, 0x44, 0x52, 0xc1, 0x37, 0x26, 0xf9, 0x7a, 0x7b, 0x11, 0x82,
|
0x59, 0x79, 0xba, 0x2e, 0x0f, 0x91, 0x0e, 0x17, 0x19, 0x4f, 0xca, 0xf9, 0x2e, 0x08, 0xbe, 0xfe,
|
||||||
0xa8, 0xa8, 0xfb, 0x7e, 0xa7, 0x55, 0x75, 0x03, 0x5d, 0xc1, 0x9c, 0x3e, 0xfd, 0x50, 0x1e, 0xe2,
|
0x9e, 0x87, 0x20, 0x32, 0x6a, 0xd5, 0xed, 0xb6, 0x6b, 0xb6, 0xa7, 0x2a, 0x98, 0x55, 0xa7, 0x1f,
|
||||||
0xfb, 0x70, 0x4d, 0x72, 0x7c, 0x4c, 0x9a, 0x8d, 0x1a, 0xe1, 0x34, 0x18, 0x28, 0xe6, 0x65, 0x98,
|
0x89, 0x43, 0xfc, 0x00, 0x6e, 0x08, 0x8e, 0x4f, 0x48, 0xab, 0x59, 0x27, 0x3e, 0xf5, 0x86, 0x8a,
|
||||||
0x75, 0xa8, 0x3f, 0xc8, 0x31, 0x23, 0xce, 0xb6, 0xce, 0x55, 0xf5, 0x95, 0x01, 0x2f, 0x25, 0x44,
|
0x79, 0x05, 0x66, 0x2c, 0xea, 0x0e, 0x73, 0x4c, 0xf3, 0xb3, 0xf5, 0x53, 0x55, 0x7d, 0xad, 0xc1,
|
||||||
0xd3, 0x85, 0xad, 0xc2, 0x33, 0x21, 0x55, 0x3c, 0x62, 0x08, 0xfb, 0x3f, 0x96, 0x16, 0x0e, 0xd1,
|
0xcb, 0x31, 0xd1, 0x54, 0x61, 0x05, 0xb8, 0x1c, 0x50, 0x45, 0x23, 0x06, 0xb0, 0xff, 0x63, 0x69,
|
||||||
0xb6, 0xba, 0xe7, 0xcb, 0x5c, 0xcf, 0x4d, 0x3d, 0x44, 0x3d, 0xd7, 0xb4, 0x21, 0xc2, 0xf7, 0x75,
|
0xc1, 0x10, 0x6d, 0xc8, 0x7b, 0x3e, 0xcf, 0xf5, 0xdc, 0x56, 0x43, 0xd4, 0x77, 0x4d, 0x1a, 0x22,
|
||||||
0xb2, 0x5d, 0x4e, 0x03, 0xe2, 0xa5, 0x27, 0x43, 0x0b, 0x30, 0x7e, 0xe0, 0x1e, 0xe9, 0x79, 0x13,
|
0xfc, 0x40, 0x25, 0xdb, 0xf1, 0xa9, 0x47, 0x9c, 0xe4, 0x64, 0x68, 0x0e, 0x26, 0xf6, 0xec, 0x03,
|
||||||
0xcb, 0x48, 0xfa, 0x4d, 0x9d, 0xbe, 0x17, 0x4c, 0xa7, 0xcf, 0xc3, 0x44, 0x97, 0x34, 0x3b, 0x61,
|
0x35, 0x6f, 0x7c, 0x19, 0x4a, 0xbf, 0xa6, 0xd2, 0xf7, 0x83, 0xa9, 0xf4, 0x39, 0x98, 0xec, 0x91,
|
||||||
0x72, 0xb5, 0xc1, 0x6f, 0xc2, 0x82, 0x1e, 0xa5, 0xda, 0xa5, 0x8a, 0x5c, 0x85, 0x67, 0x23, 0x7e,
|
0x56, 0x37, 0x48, 0x2e, 0x37, 0xf8, 0x2d, 0x98, 0x53, 0xa3, 0x54, 0x3f, 0x57, 0x91, 0x05, 0x78,
|
||||||
0x3a, 0x05, 0x82, 0xac, 0x98, 0x7d, 0xe9, 0x35, 0x5b, 0x91, 0x6b, 0x5c, 0x06, 0x24, 0x0d, 0xf7,
|
0x21, 0xe4, 0xa7, 0x52, 0x20, 0x48, 0xf3, 0xd9, 0x17, 0x5e, 0x33, 0x15, 0xb1, 0xc6, 0x65, 0x40,
|
||||||
0x0e, 0x1f, 0x50, 0x8f, 0x85, 0x29, 0x10, 0x64, 0xe5, 0x2f, 0x46, 0xc5, 0x97, 0xeb, 0x48, 0xf0,
|
0xc2, 0x70, 0x77, 0xff, 0x21, 0x75, 0x58, 0x90, 0x02, 0x41, 0x5a, 0xfc, 0x62, 0x64, 0x7c, 0xb1,
|
||||||
0x1d, 0xdd, 0x8f, 0xd0, 0x47, 0x87, 0xb7, 0x21, 0xdb, 0xa4, 0x9e, 0x80, 0x1a, 0x2f, 0xce, 0x94,
|
0x0e, 0x05, 0xdf, 0x56, 0xfd, 0x08, 0x7c, 0x54, 0x78, 0x13, 0xd2, 0x2d, 0xea, 0x70, 0xa8, 0x89,
|
||||||
0xaf, 0x5a, 0x17, 0x3f, 0x51, 0xd6, 0x03, 0xea, 0x55, 0xa4, 0x21, 0x3e, 0x81, 0xe7, 0xd5, 0x4d,
|
0xe2, 0x74, 0xf9, 0xba, 0x31, 0xfa, 0x89, 0x32, 0x1e, 0x52, 0xa7, 0x22, 0x0c, 0xf1, 0x11, 0xbc,
|
||||||
0x34, 0xa9, 0x73, 0x90, 0x92, 0x1e, 0xed, 0x00, 0xf4, 0xdf, 0x2a, 0xd9, 0xda, 0x99, 0xf2, 0x8a,
|
0x28, 0x6f, 0xa2, 0x45, 0xad, 0xbd, 0x84, 0xf4, 0x68, 0x1b, 0x60, 0xf0, 0x56, 0x89, 0xd6, 0x4e,
|
||||||
0xa5, 0x7e, 0x33, 0x96, 0x78, 0xd8, 0x2c, 0xf5, 0x3e, 0xea, 0x87, 0xcd, 0x7a, 0xd8, 0xbf, 0xa9,
|
0x97, 0x97, 0x0c, 0xf9, 0x9b, 0x31, 0xf8, 0xc3, 0x66, 0xc8, 0xf7, 0x51, 0x3d, 0x6c, 0xc6, 0xa3,
|
||||||
0x4a, 0xc4, 0x33, 0x52, 0xc6, 0xcf, 0x06, 0x5c, 0x19, 0xcc, 0xaf, 0x4b, 0xd9, 0x81, 0x1c, 0x3f,
|
0xc1, 0x4d, 0x55, 0x42, 0x9e, 0xa1, 0x32, 0x7e, 0xd6, 0xe0, 0xea, 0x70, 0x7e, 0x55, 0xca, 0x36,
|
||||||
0xdc, 0x8f, 0x54, 0xb3, 0x9a, 0x54, 0xcd, 0x5e, 0x40, 0x7c, 0x46, 0x1c, 0x11, 0x5a, 0x44, 0xd8,
|
0x64, 0xfd, 0xfd, 0x6a, 0xa8, 0x9a, 0x42, 0x5c, 0x35, 0xbb, 0x1e, 0x71, 0x19, 0xb1, 0x78, 0x68,
|
||||||
0xce, 0x3e, 0xf9, 0x63, 0x29, 0x53, 0x99, 0xe4, 0xb2, 0x35, 0xe8, 0xfd, 0x0b, 0xa0, 0x57, 0x53,
|
0x1e, 0x61, 0x23, 0xfd, 0xec, 0x8f, 0x85, 0x54, 0x25, 0xe3, 0x8b, 0xd6, 0xa0, 0x7b, 0x23, 0xa0,
|
||||||
0xa1, 0x15, 0x44, 0x94, 0x1a, 0x2f, 0x46, 0x51, 0xb7, 0x9b, 0x94, 0xb6, 0x74, 0x6d, 0xd8, 0x86,
|
0x0b, 0x89, 0xd0, 0x12, 0x22, 0x4c, 0x8d, 0xe7, 0xc3, 0xa8, 0x1b, 0x2d, 0x4a, 0xdb, 0xaa, 0x36,
|
||||||
0x17, 0xce, 0x7d, 0xe9, 0x8f, 0x54, 0x55, 0x1c, 0xe8, 0x0b, 0x57, 0x1b, 0x9c, 0xd7, 0x37, 0xfe,
|
0x6c, 0xc2, 0xb5, 0x53, 0x5f, 0x06, 0x23, 0x55, 0xe3, 0x07, 0xea, 0xc2, 0xe5, 0x06, 0xe7, 0xd4,
|
||||||
0x90, 0x04, 0xa4, 0x15, 0xb6, 0x1c, 0xef, 0xea, 0x3b, 0x0d, 0x4f, 0x75, 0x88, 0x77, 0x60, 0xb2,
|
0x8d, 0x3f, 0x22, 0x1e, 0x69, 0x07, 0x2d, 0xc7, 0x3b, 0xea, 0x4e, 0x83, 0x53, 0x15, 0xe2, 0x5d,
|
||||||
0x2d, 0x4f, 0x64, 0x8c, 0x99, 0x72, 0x21, 0xa9, 0x0f, 0xca, 0x2f, 0x2c, 0x5f, 0xf9, 0xe0, 0x7b,
|
0xc8, 0x74, 0xc4, 0x89, 0x88, 0x31, 0x5d, 0xce, 0xc7, 0xf5, 0x41, 0xfa, 0x05, 0xe5, 0x4b, 0x1f,
|
||||||
0x9a, 0x7a, 0x57, 0x88, 0x88, 0x73, 0x87, 0x34, 0x9b, 0xe9, 0xbf, 0x9d, 0x3c, 0x4c, 0x34, 0xfc,
|
0x7c, 0x5f, 0x51, 0xef, 0x70, 0x11, 0xb1, 0x36, 0x49, 0xab, 0x95, 0xfc, 0xdb, 0xc9, 0xc1, 0x64,
|
||||||
0x76, 0x87, 0xcb, 0x6e, 0xcd, 0x56, 0xd4, 0x06, 0xdf, 0xd0, 0x55, 0x46, 0x23, 0xf5, 0xa7, 0xba,
|
0xd3, 0xed, 0x74, 0x7d, 0xd1, 0xad, 0x99, 0x8a, 0xdc, 0xe0, 0x5b, 0xaa, 0xca, 0x70, 0xa4, 0xc1,
|
||||||
0x46, 0x38, 0x09, 0xa7, 0x5a, 0xac, 0xf1, 0xab, 0x30, 0x7f, 0x97, 0xd7, 0xa3, 0x09, 0x11, 0x64,
|
0x54, 0xd7, 0x89, 0x4f, 0x82, 0xa9, 0xe6, 0x6b, 0xfc, 0x1e, 0x5c, 0xda, 0xf2, 0x1b, 0xe1, 0x84,
|
||||||
0x49, 0xe0, 0xb1, 0xd0, 0x4a, 0xac, 0xcb, 0xff, 0xcc, 0xc3, 0x84, 0x8c, 0x8a, 0xbe, 0x37, 0x20,
|
0x08, 0xd2, 0xc4, 0x73, 0x58, 0x60, 0xc5, 0xd7, 0xe8, 0x1a, 0x64, 0x1d, 0xc2, 0xaa, 0x16, 0xe9,
|
||||||
0xa7, 0x9f, 0x33, 0xb4, 0x91, 0x54, 0xe2, 0x05, 0xaa, 0x65, 0x6e, 0x8e, 0x66, 0xac, 0x50, 0x71,
|
0xa8, 0x67, 0x28, 0xe3, 0x10, 0xb6, 0x49, 0x3a, 0xb8, 0x00, 0x57, 0xb6, 0x98, 0xdf, 0x6c, 0x13,
|
||||||
0xe9, 0xd3, 0xdf, 0xfe, 0xfa, 0x6e, 0x6c, 0x03, 0xad, 0xd9, 0x09, 0x22, 0xa9, 0x1f, 0x39, 0xfb,
|
0xdf, 0xbe, 0x47, 0x06, 0xcd, 0x98, 0x83, 0x09, 0x87, 0xc8, 0x10, 0xe9, 0x0a, 0x5f, 0x96, 0xff,
|
||||||
0x58, 0x77, 0xe3, 0x04, 0xfd, 0x62, 0xc0, 0x5c, 0x4c, 0x47, 0x50, 0x69, 0x68, 0xca, 0x8b, 0x54,
|
0xb9, 0x0c, 0x93, 0x82, 0x0b, 0x7d, 0xaf, 0x41, 0x56, 0x3d, 0x88, 0x68, 0x35, 0xae, 0x49, 0x23,
|
||||||
0xcb, 0x2c, 0x5f, 0xc6, 0x45, 0xb3, 0xde, 0x92, 0xac, 0x65, 0x74, 0x33, 0x89, 0x35, 0x14, 0xb1,
|
0x74, 0x4f, 0x5f, 0x1b, 0xcf, 0x58, 0x22, 0xe0, 0xd2, 0x67, 0xbf, 0xfd, 0xf5, 0xdd, 0x85, 0x55,
|
||||||
0x73, 0xc8, 0xbf, 0x1a, 0xb0, 0x30, 0x28, 0x12, 0xe8, 0xf5, 0xa1, 0x08, 0x09, 0x0a, 0x65, 0xbe,
|
0xb4, 0x6c, 0xc6, 0xc8, 0xac, 0x7a, 0x26, 0xcd, 0x43, 0xd5, 0xcf, 0x23, 0xf4, 0x8b, 0x06, 0xb3,
|
||||||
0x71, 0x49, 0x2f, 0xcd, 0xfe, 0x9e, 0x64, 0xbf, 0x8d, 0x6e, 0x25, 0xb1, 0x77, 0x43, 0xcf, 0x3e,
|
0x11, 0x25, 0x42, 0xa5, 0x33, 0x53, 0x8e, 0xd2, 0x3d, 0xbd, 0x7c, 0x1e, 0x17, 0xc5, 0x7a, 0x47,
|
||||||
0x7e, 0x54, 0x09, 0x4f, 0xd0, 0x0f, 0x06, 0xe4, 0xb4, 0x40, 0xa4, 0x0c, 0x44, 0x5c, 0x81, 0x52,
|
0xb0, 0x96, 0xd1, 0xed, 0x38, 0xd6, 0x40, 0x06, 0x4f, 0x21, 0xff, 0xaa, 0xc1, 0xdc, 0xb0, 0xcc,
|
||||||
0x06, 0x62, 0x40, 0x73, 0x70, 0x59, 0x82, 0x6e, 0xa2, 0xf5, 0x24, 0x50, 0x2d, 0x41, 0x2c, 0xd2,
|
0xa0, 0x37, 0xce, 0x44, 0x88, 0xd1, 0x38, 0xfd, 0xcd, 0x73, 0x7a, 0x29, 0xf6, 0x0f, 0x04, 0xfb,
|
||||||
0xde, 0x9f, 0x0c, 0xc8, 0x69, 0xf1, 0x48, 0x41, 0x8b, 0xeb, 0x55, 0x0a, 0xda, 0x80, 0x1e, 0xe1,
|
0x5d, 0x74, 0x27, 0x8e, 0xbd, 0x17, 0x78, 0x0e, 0xf0, 0xc3, 0x5a, 0x7a, 0x84, 0x7e, 0xd0, 0x20,
|
||||||
0xb7, 0x24, 0x5a, 0x09, 0xd9, 0x49, 0x68, 0x4c, 0x39, 0xf4, 0xc9, 0xec, 0xe3, 0x03, 0xf7, 0xe8,
|
0xab, 0x24, 0x26, 0x61, 0x20, 0xa2, 0x1a, 0x96, 0x30, 0x10, 0x43, 0xaa, 0x85, 0xcb, 0x02, 0x74,
|
||||||
0x04, 0x7d, 0x6d, 0x40, 0x56, 0xc8, 0x0e, 0x2a, 0xa6, 0x4c, 0x5d, 0x4f, 0xd1, 0xcc, 0xb5, 0x11,
|
0x0d, 0xad, 0xc4, 0x81, 0x2a, 0x11, 0x63, 0xa1, 0xf6, 0xfe, 0xa4, 0x41, 0x56, 0xc9, 0x4f, 0x02,
|
||||||
0x2c, 0x35, 0x96, 0x2d, 0xb1, 0xd6, 0xd0, 0x6a, 0xf2, 0x58, 0xd6, 0x62, 0xed, 0xfa, 0xd6, 0x80,
|
0x5a, 0x54, 0xf1, 0x12, 0xd0, 0x86, 0x14, 0x0d, 0xbf, 0x2d, 0xd0, 0x4a, 0xc8, 0x8c, 0x43, 0x63,
|
||||||
0x49, 0x25, 0x54, 0x68, 0x7d, 0x68, 0x9a, 0x98, 0x02, 0x9a, 0x1b, 0x23, 0xd9, 0x6a, 0x28, 0x4b,
|
0xd2, 0x61, 0x40, 0x66, 0x1e, 0xee, 0xd9, 0x07, 0x47, 0xe8, 0x1b, 0x0d, 0xd2, 0x5c, 0xb8, 0x50,
|
||||||
0x42, 0x15, 0xd1, 0x8a, 0x9d, 0xf8, 0xc7, 0xaf, 0x14, 0x13, 0xfb, 0x58, 0x48, 0x99, 0xbc, 0xc2,
|
0x31, 0x61, 0xea, 0xfa, 0x9a, 0xa8, 0x2f, 0x8f, 0x61, 0xa9, 0xb0, 0x4c, 0x81, 0xb5, 0x8c, 0x0a,
|
||||||
0xe9, 0x9e, 0xe8, 0xa0, 0x1b, 0xc3, 0x47, 0x66, 0x40, 0x1c, 0x4d, 0x6b, 0x54, 0xf3, 0x51, 0x1f,
|
0xf1, 0x63, 0x59, 0x8f, 0xb4, 0xeb, 0x5b, 0x0d, 0x32, 0x52, 0xea, 0xd0, 0xca, 0x99, 0x69, 0x22,
|
||||||
0x9d, 0xaa, 0x70, 0x89, 0xf1, 0xfd, 0x68, 0x00, 0xf4, 0xf5, 0x04, 0x8d, 0x90, 0x31, 0x2a, 0x49,
|
0x1a, 0xaa, 0xaf, 0x8e, 0x65, 0xab, 0xa0, 0x0c, 0x01, 0x55, 0x44, 0x4b, 0x66, 0xec, 0x9f, 0xcf,
|
||||||
0xa6, 0x3d, 0xb2, 0xbd, 0x46, 0xdc, 0x90, 0x88, 0xd7, 0xd1, 0x2b, 0xc3, 0x11, 0xa5, 0x7e, 0xa1,
|
0x42, 0x8e, 0xcc, 0x43, 0x2e, 0x86, 0xe2, 0x0a, 0xa7, 0xfa, 0xb2, 0x85, 0x6e, 0x9d, 0x3d, 0x32,
|
||||||
0x2f, 0x0c, 0x98, 0x54, 0x6a, 0x93, 0x72, 0xa1, 0x31, 0x81, 0x4b, 0xb9, 0xd0, 0xb8, 0xec, 0xe1,
|
0x43, 0xf2, 0xaa, 0x1b, 0xe3, 0x9a, 0x8f, 0xfb, 0xe8, 0xd4, 0xb8, 0x4b, 0x84, 0xef, 0x47, 0x0d,
|
||||||
0x15, 0x09, 0xb4, 0x8c, 0x0a, 0x49, 0x40, 0x4a, 0xe0, 0x64, 0xa3, 0xfa, 0x92, 0x94, 0xd2, 0xa8,
|
0x60, 0xa0, 0x48, 0x68, 0x8c, 0x8c, 0x61, 0x51, 0xd3, 0xcd, 0xb1, 0xed, 0x15, 0xe2, 0xaa, 0x40,
|
||||||
0x73, 0x2a, 0x98, 0xd2, 0xa8, 0xf3, 0x5a, 0x97, 0xde, 0x28, 0x26, 0x7d, 0xf6, 0x1d, 0x41, 0xf3,
|
0xbc, 0x89, 0x5e, 0x3d, 0x1b, 0x51, 0x28, 0x20, 0xfa, 0x52, 0x83, 0x8c, 0xd4, 0xab, 0x84, 0x0b,
|
||||||
0xa5, 0x01, 0x39, 0xad, 0x82, 0x68, 0x25, 0x29, 0x53, 0x5c, 0x26, 0xcd, 0xc4, 0x59, 0xfc, 0x80,
|
0x8d, 0x48, 0x64, 0xc2, 0x85, 0x46, 0x85, 0x13, 0x2f, 0x09, 0xa0, 0x45, 0x94, 0x8f, 0x03, 0x92,
|
||||||
0x79, 0x77, 0xc5, 0x17, 0xb7, 0xd3, 0xda, 0x3b, 0xec, 0xf1, 0x14, 0x25, 0x0f, 0x46, 0xcb, 0x49,
|
0x12, 0x29, 0x1a, 0x35, 0x10, 0xb5, 0x84, 0x46, 0x9d, 0xd2, 0xd1, 0x84, 0x46, 0x9d, 0x56, 0xcb,
|
||||||
0x3c, 0x2e, 0xaf, 0x4b, 0x98, 0xed, 0xed, 0x27, 0xa7, 0x05, 0xe3, 0xe9, 0x69, 0xc1, 0xf8, 0xf3,
|
0xe4, 0x46, 0x31, 0xe1, 0x53, 0xb5, 0x38, 0xcd, 0x57, 0x1a, 0x64, 0x95, 0x8e, 0xa2, 0xa5, 0xb8,
|
||||||
0xb4, 0x60, 0x7c, 0x73, 0x56, 0xc8, 0x3c, 0x3d, 0x2b, 0x64, 0x7e, 0x3f, 0x2b, 0x64, 0x3e, 0x29,
|
0x4c, 0x51, 0xa1, 0xd5, 0x63, 0x67, 0xf1, 0x43, 0xe6, 0x6c, 0xf1, 0x2f, 0x76, 0xb7, 0xbd, 0xbb,
|
||||||
0x7a, 0x0d, 0x5e, 0xef, 0x54, 0x2d, 0x87, 0xb6, 0x6c, 0x5e, 0x27, 0x01, 0x6b, 0xb0, 0x48, 0xb4,
|
0xdf, 0xe7, 0x29, 0x0a, 0x1e, 0x8c, 0x16, 0xe3, 0x78, 0x6c, 0xbf, 0x21, 0x61, 0x9e, 0x68, 0x30,
|
||||||
0x43, 0x19, 0x8f, 0x1f, 0xb5, 0x5d, 0x56, 0x9d, 0x94, 0xff, 0x40, 0xbe, 0xf6, 0x6f, 0x00, 0x00,
|
0x1d, 0x52, 0xe5, 0xb1, 0x81, 0x62, 0xaf, 0x6d, 0x84, 0xc4, 0xe3, 0x35, 0x81, 0xb3, 0x84, 0x5e,
|
||||||
0x00, 0xff, 0xff, 0xb7, 0x54, 0x23, 0x90, 0x21, 0x0f, 0x00, 0x00,
|
0x8b, 0xc5, 0x51, 0x4e, 0x55, 0x87, 0xb0, 0x8d, 0x8d, 0x67, 0xc7, 0x79, 0xed, 0xf9, 0x71, 0x5e,
|
||||||
|
0xfb, 0xf3, 0x38, 0xaf, 0x3d, 0x39, 0xc9, 0xa7, 0x9e, 0x9f, 0xe4, 0x53, 0xbf, 0x9f, 0xe4, 0x53,
|
||||||
|
0x9f, 0x16, 0x9d, 0xa6, 0xdf, 0xe8, 0xd6, 0x0c, 0x8b, 0xb6, 0x4d, 0xbf, 0x41, 0x3c, 0xd6, 0x64,
|
||||||
|
0xa1, 0x88, 0xfb, 0x22, 0xa6, 0x7f, 0xd0, 0xb1, 0x59, 0x2d, 0x23, 0xfe, 0x2b, 0x7e, 0xfd, 0xdf,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0xa4, 0x09, 0x32, 0xf6, 0x0f, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
@ -1238,6 +1298,8 @@ type QueryClient interface {
|
|||||||
StaticCall(ctx context.Context, in *QueryStaticCallRequest, opts ...grpc.CallOption) (*QueryStaticCallResponse, error)
|
StaticCall(ctx context.Context, in *QueryStaticCallRequest, opts ...grpc.CallOption) (*QueryStaticCallResponse, error)
|
||||||
// EthCall implements the `eth_call` rpc api
|
// EthCall implements the `eth_call` rpc api
|
||||||
EthCall(ctx context.Context, in *EthCallRequest, opts ...grpc.CallOption) (*MsgEthereumTxResponse, error)
|
EthCall(ctx context.Context, in *EthCallRequest, opts ...grpc.CallOption) (*MsgEthereumTxResponse, error)
|
||||||
|
// EstimateGas implements the `eth_estimateGas` rpc api
|
||||||
|
EstimateGas(ctx context.Context, in *EthCallRequest, opts ...grpc.CallOption) (*EstimateGasResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type queryClient struct {
|
type queryClient struct {
|
||||||
@ -1356,6 +1418,15 @@ func (c *queryClient) EthCall(ctx context.Context, in *EthCallRequest, opts ...g
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *queryClient) EstimateGas(ctx context.Context, in *EthCallRequest, opts ...grpc.CallOption) (*EstimateGasResponse, error) {
|
||||||
|
out := new(EstimateGasResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/ethermint.evm.v1alpha1.Query/EstimateGas", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// QueryServer is the server API for Query service.
|
// QueryServer is the server API for Query service.
|
||||||
type QueryServer interface {
|
type QueryServer interface {
|
||||||
// Account queries an Ethereum account.
|
// Account queries an Ethereum account.
|
||||||
@ -1383,6 +1454,8 @@ type QueryServer interface {
|
|||||||
StaticCall(context.Context, *QueryStaticCallRequest) (*QueryStaticCallResponse, error)
|
StaticCall(context.Context, *QueryStaticCallRequest) (*QueryStaticCallResponse, error)
|
||||||
// EthCall implements the `eth_call` rpc api
|
// EthCall implements the `eth_call` rpc api
|
||||||
EthCall(context.Context, *EthCallRequest) (*MsgEthereumTxResponse, error)
|
EthCall(context.Context, *EthCallRequest) (*MsgEthereumTxResponse, error)
|
||||||
|
// EstimateGas implements the `eth_estimateGas` rpc api
|
||||||
|
EstimateGas(context.Context, *EthCallRequest) (*EstimateGasResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnimplementedQueryServer can be embedded to have forward compatible implementations.
|
// UnimplementedQueryServer can be embedded to have forward compatible implementations.
|
||||||
@ -1425,6 +1498,9 @@ func (*UnimplementedQueryServer) StaticCall(ctx context.Context, req *QueryStati
|
|||||||
func (*UnimplementedQueryServer) EthCall(ctx context.Context, req *EthCallRequest) (*MsgEthereumTxResponse, error) {
|
func (*UnimplementedQueryServer) EthCall(ctx context.Context, req *EthCallRequest) (*MsgEthereumTxResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method EthCall not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method EthCall not implemented")
|
||||||
}
|
}
|
||||||
|
func (*UnimplementedQueryServer) EstimateGas(ctx context.Context, req *EthCallRequest) (*EstimateGasResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method EstimateGas not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func RegisterQueryServer(s grpc1.Server, srv QueryServer) {
|
func RegisterQueryServer(s grpc1.Server, srv QueryServer) {
|
||||||
s.RegisterService(&_Query_serviceDesc, srv)
|
s.RegisterService(&_Query_serviceDesc, srv)
|
||||||
@ -1646,6 +1722,24 @@ func _Query_EthCall_Handler(srv interface{}, ctx context.Context, dec func(inter
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _Query_EstimateGas_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(EthCallRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(QueryServer).EstimateGas(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/ethermint.evm.v1alpha1.Query/EstimateGas",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(QueryServer).EstimateGas(ctx, req.(*EthCallRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
var _Query_serviceDesc = grpc.ServiceDesc{
|
var _Query_serviceDesc = grpc.ServiceDesc{
|
||||||
ServiceName: "ethermint.evm.v1alpha1.Query",
|
ServiceName: "ethermint.evm.v1alpha1.Query",
|
||||||
HandlerType: (*QueryServer)(nil),
|
HandlerType: (*QueryServer)(nil),
|
||||||
@ -1698,6 +1792,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "EthCall",
|
MethodName: "EthCall",
|
||||||
Handler: _Query_EthCall_Handler,
|
Handler: _Query_EthCall_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "EstimateGas",
|
||||||
|
Handler: _Query_EstimateGas_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "ethermint/evm/v1alpha1/query.proto",
|
Metadata: "ethermint/evm/v1alpha1/query.proto",
|
||||||
@ -2456,6 +2554,11 @@ func (m *EthCallRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||||||
_ = i
|
_ = i
|
||||||
var l int
|
var l int
|
||||||
_ = l
|
_ = l
|
||||||
|
if m.GasCap != 0 {
|
||||||
|
i = encodeVarintQuery(dAtA, i, uint64(m.GasCap))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x10
|
||||||
|
}
|
||||||
if len(m.Args) > 0 {
|
if len(m.Args) > 0 {
|
||||||
i -= len(m.Args)
|
i -= len(m.Args)
|
||||||
copy(dAtA[i:], m.Args)
|
copy(dAtA[i:], m.Args)
|
||||||
@ -2466,6 +2569,34 @@ func (m *EthCallRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||||||
return len(dAtA) - i, nil
|
return len(dAtA) - i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *EstimateGasResponse) Marshal() (dAtA []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
dAtA = make([]byte, size)
|
||||||
|
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dAtA[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EstimateGasResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
size := m.Size()
|
||||||
|
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EstimateGasResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||||
|
i := len(dAtA)
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if m.Gas != 0 {
|
||||||
|
i = encodeVarintQuery(dAtA, i, uint64(m.Gas))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x8
|
||||||
|
}
|
||||||
|
return len(dAtA) - i, nil
|
||||||
|
}
|
||||||
|
|
||||||
func encodeVarintQuery(dAtA []byte, offset int, v uint64) int {
|
func encodeVarintQuery(dAtA []byte, offset int, v uint64) int {
|
||||||
offset -= sovQuery(v)
|
offset -= sovQuery(v)
|
||||||
base := offset
|
base := offset
|
||||||
@ -2802,6 +2933,21 @@ func (m *EthCallRequest) Size() (n int) {
|
|||||||
if l > 0 {
|
if l > 0 {
|
||||||
n += 1 + l + sovQuery(uint64(l))
|
n += 1 + l + sovQuery(uint64(l))
|
||||||
}
|
}
|
||||||
|
if m.GasCap != 0 {
|
||||||
|
n += 1 + sovQuery(uint64(m.GasCap))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EstimateGasResponse) Size() (n int) {
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if m.Gas != 0 {
|
||||||
|
n += 1 + sovQuery(uint64(m.Gas))
|
||||||
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4890,6 +5036,94 @@ func (m *EthCallRequest) Unmarshal(dAtA []byte) error {
|
|||||||
m.Args = []byte{}
|
m.Args = []byte{}
|
||||||
}
|
}
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
|
case 2:
|
||||||
|
if wireType != 0 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field GasCap", wireType)
|
||||||
|
}
|
||||||
|
m.GasCap = 0
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowQuery
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
m.GasCap |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipQuery(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||||
|
return ErrInvalidLengthQuery
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *EstimateGasResponse) Unmarshal(dAtA []byte) error {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowQuery
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: EstimateGasResponse: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: EstimateGasResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 0 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Gas", wireType)
|
||||||
|
}
|
||||||
|
m.Gas = 0
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowQuery
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
m.Gas |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
iNdEx = preIndex
|
iNdEx = preIndex
|
||||||
skippy, err := skipQuery(dAtA[iNdEx:])
|
skippy, err := skipQuery(dAtA[iNdEx:])
|
||||||
|
@ -611,6 +611,42 @@ func local_request_Query_EthCall_0(ctx context.Context, marshaler runtime.Marsha
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
filter_Query_EstimateGas_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||||
|
)
|
||||||
|
|
||||||
|
func request_Query_EstimateGas_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq EthCallRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := req.ParseForm(); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_EstimateGas_0); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.EstimateGas(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_Query_EstimateGas_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq EthCallRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := req.ParseForm(); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_EstimateGas_0); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.EstimateGas(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
|
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
|
||||||
// UnaryRPC :call QueryServer directly.
|
// UnaryRPC :call QueryServer directly.
|
||||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||||
@ -857,6 +893,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_Query_EstimateGas_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_Query_EstimateGas_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_Query_EstimateGas_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1138,6 +1194,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_Query_EstimateGas_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_Query_EstimateGas_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_Query_EstimateGas_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,6 +1241,8 @@ var (
|
|||||||
pattern_Query_StaticCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "static_call"}, "", runtime.AssumeColonVerbOpt(true)))
|
pattern_Query_StaticCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "static_call"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||||
|
|
||||||
pattern_Query_EthCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "eth_call"}, "", runtime.AssumeColonVerbOpt(true)))
|
pattern_Query_EthCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "eth_call"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||||
|
|
||||||
|
pattern_Query_EstimateGas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "estimate_gas"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -1191,4 +1269,6 @@ var (
|
|||||||
forward_Query_StaticCall_0 = runtime.ForwardResponseMessage
|
forward_Query_StaticCall_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_Query_EthCall_0 = runtime.ForwardResponseMessage
|
forward_Query_EthCall_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_Query_EstimateGas_0 = runtime.ForwardResponseMessage
|
||||||
)
|
)
|
||||||
|
@ -69,3 +69,24 @@ func UnwrapEthereumMsg(tx *sdk.Tx) (*MsgEthereumTx, error) {
|
|||||||
|
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinSearch execute the binary search and hone in on an executable gas limit
|
||||||
|
func BinSearch(lo uint64, hi uint64, executable func(uint64) (bool, *MsgEthereumTxResponse, error)) (uint64, error) {
|
||||||
|
for lo+1 < hi {
|
||||||
|
mid := (hi + lo) / 2
|
||||||
|
failed, _, err := executable(mid)
|
||||||
|
|
||||||
|
// If the error is not nil(consensus error), it means the provided message
|
||||||
|
// call or transaction will never be accepted no matter how much gas it is
|
||||||
|
// assigned. Return the error directly, don't struggle any more.
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if failed {
|
||||||
|
lo = mid
|
||||||
|
} else {
|
||||||
|
hi = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hi, nil
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package types_test
|
package types_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -79,3 +80,21 @@ func TestUnwrapEthererumMsg(t *testing.T) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, msg_, msg)
|
require.Equal(t, msg_, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBinSearch(t *testing.T) {
|
||||||
|
success_executable := func(gas uint64) (bool, *evmtypes.MsgEthereumTxResponse, error) {
|
||||||
|
target := uint64(21000)
|
||||||
|
return gas < target, nil, nil
|
||||||
|
}
|
||||||
|
failed_executable := func(gas uint64) (bool, *evmtypes.MsgEthereumTxResponse, error) {
|
||||||
|
return true, nil, errors.New("contract failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
gas, err := evmtypes.BinSearch(20000, 21001, success_executable)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, gas, uint64(21000))
|
||||||
|
|
||||||
|
gas, err = evmtypes.BinSearch(20000, 21001, failed_executable)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, gas, uint64(0))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user