forked from cerc-io/laconicd-deprecated
eth_estimateGas (#128)
* Draft eth_estimateGas * implemented eth_estimateGas * refactored doCall to be used for both eth_call and eth_estiamteGas * updated to reflect requested changes * moved GenerateFromArgs func * removed todo * revert comment * fixes dereference issue * gofmted
This commit is contained in:
+89
-17
@@ -9,8 +9,9 @@ import (
|
||||
|
||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||
emintkeys "github.com/cosmos/ethermint/keys"
|
||||
"github.com/cosmos/ethermint/rpc/args"
|
||||
params "github.com/cosmos/ethermint/rpc/args"
|
||||
emint "github.com/cosmos/ethermint/types"
|
||||
etypes "github.com/cosmos/ethermint/types"
|
||||
"github.com/cosmos/ethermint/utils"
|
||||
"github.com/cosmos/ethermint/version"
|
||||
"github.com/cosmos/ethermint/x/evm"
|
||||
@@ -23,7 +24,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authutils "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
@@ -249,7 +248,7 @@ func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil
|
||||
}
|
||||
|
||||
// SendTransaction sends an Ethereum transaction.
|
||||
func (e *PublicEthAPI) SendTransaction(args args.SendTxArgs) (common.Hash, error) {
|
||||
func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, error) {
|
||||
// TODO: Change this functionality to find an unlocked account by address
|
||||
if e.key == nil || !bytes.Equal(e.key.PubKey().Address().Bytes(), args.From.Bytes()) {
|
||||
return common.Hash{}, keystore.ErrLocked
|
||||
@@ -262,7 +261,7 @@ func (e *PublicEthAPI) SendTransaction(args args.SendTxArgs) (common.Hash, error
|
||||
}
|
||||
|
||||
// Assemble transaction from fields
|
||||
tx, err := types.GenerateFromArgs(args, e.cliCtx)
|
||||
tx, err := e.GenerateFromArgs(args)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
@@ -341,8 +340,14 @@ type CallArgs struct {
|
||||
|
||||
// Call performs a raw contract call.
|
||||
func (e *PublicEthAPI) Call(args CallArgs, blockNr rpc.BlockNumber, overrides *map[common.Address]account) (hexutil.Bytes, error) {
|
||||
result, err := e.doCall(args, blockNr, vm.Config{}, big.NewInt(emint.DefaultRPCGasLimit))
|
||||
return (hexutil.Bytes)(result), err
|
||||
result, err := e.doCall(args, blockNr, big.NewInt(emint.DefaultRPCGasLimit))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
_, _, ret, err := types.DecodeReturnData(result.Data)
|
||||
|
||||
return (hexutil.Bytes)(ret), err
|
||||
}
|
||||
|
||||
// account indicates the overriding fields of account during the execution of
|
||||
@@ -360,7 +365,7 @@ type account struct {
|
||||
}
|
||||
|
||||
// DoCall performs a simulated call operation through the evm
|
||||
func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, globalGasCap *big.Int) ([]byte, error) {
|
||||
func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasCap *big.Int) (sdk.Result, error) {
|
||||
// Set height for historical queries
|
||||
ctx := e.cliCtx.WithHeight(blockNr.Int64())
|
||||
|
||||
@@ -421,28 +426,31 @@ func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.C
|
||||
txEncoder := authutils.GetTxEncoder(ctx.Codec)
|
||||
txBytes, err := txEncoder(tx)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return sdk.Result{}, err
|
||||
}
|
||||
|
||||
// Transaction simulation through query
|
||||
res, _, err := ctx.QueryWithData("app/simulate", txBytes)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return sdk.Result{}, err
|
||||
}
|
||||
|
||||
var simResult sdk.Result
|
||||
if err = ctx.Codec.UnmarshalBinaryLengthPrefixed(res, &simResult); err != nil {
|
||||
return nil, err
|
||||
if err = e.cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res, &simResult); err != nil {
|
||||
return sdk.Result{}, err
|
||||
}
|
||||
|
||||
_, _, ret, err := types.DecodeReturnData(simResult.Data)
|
||||
|
||||
return ret, err
|
||||
return simResult, nil
|
||||
}
|
||||
|
||||
// EstimateGas estimates gas usage for the given smart contract call.
|
||||
func (e *PublicEthAPI) EstimateGas(args CallArgs, blockNum BlockNumber) hexutil.Uint64 {
|
||||
return 0
|
||||
func (e *PublicEthAPI) EstimateGas(args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) {
|
||||
result, err := e.doCall(args, blockNr, big.NewInt(emint.DefaultRPCGasLimit))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return hexutil.Uint64(result.GasUsed), nil
|
||||
}
|
||||
|
||||
// GetBlockByHash returns the block identified by hash.
|
||||
@@ -844,3 +852,67 @@ func (e *PublicEthAPI) getGasLimit() (int64, error) {
|
||||
e.gasLimit = &gasLimit
|
||||
return gasLimit, nil
|
||||
}
|
||||
|
||||
// GenerateFromArgs populates tx message with args (used in RPC API)
|
||||
func (e *PublicEthAPI) GenerateFromArgs(args params.SendTxArgs) (msg *types.EthereumTxMsg, err error) {
|
||||
var nonce uint64
|
||||
|
||||
var gasLimit uint64
|
||||
|
||||
amount := (*big.Int)(args.Value)
|
||||
|
||||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
|
||||
if args.GasPrice == nil {
|
||||
|
||||
// Set default gas price
|
||||
// TODO: Change to min gas price from context once available through server/daemon
|
||||
gasPrice = big.NewInt(etypes.DefaultGasPrice)
|
||||
}
|
||||
|
||||
if args.Nonce == nil {
|
||||
// Get nonce (sequence) from account
|
||||
from := sdk.AccAddress(args.From.Bytes())
|
||||
_, nonce, err = authtypes.NewAccountRetriever(e.cliCtx).GetAccountNumberSequence(from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
nonce = (uint64)(*args.Nonce)
|
||||
}
|
||||
|
||||
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
|
||||
return nil, fmt.Errorf(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
|
||||
}
|
||||
|
||||
// Sets input to either Input or Data, if both are set and not equal error above returns
|
||||
var input []byte
|
||||
if args.Input != nil {
|
||||
input = *args.Input
|
||||
} else if args.Data != nil {
|
||||
input = *args.Data
|
||||
}
|
||||
|
||||
if args.To == nil {
|
||||
// Contract creation
|
||||
if len(input) == 0 {
|
||||
return nil, fmt.Errorf("contract creation without any data provided")
|
||||
}
|
||||
}
|
||||
if args.Gas == nil {
|
||||
callArgs := CallArgs{
|
||||
From: &args.From,
|
||||
To: args.To,
|
||||
Gas: args.Gas,
|
||||
GasPrice: args.GasPrice,
|
||||
Value: args.Value,
|
||||
Data: args.Data,
|
||||
}
|
||||
g, _ := e.EstimateGas(callArgs, rpc.BlockNumber(e.cliCtx.Height))
|
||||
gasLimit = uint64(g)
|
||||
} else {
|
||||
gasLimit = (uint64)(*args.Gas)
|
||||
}
|
||||
|
||||
return types.NewEthereumTxMsg(nonce, args.To, amount, gasLimit, gasPrice, input), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user