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:
parent
741dfeb461
commit
69e0873dd9
3
.gitignore
vendored
3
.gitignore
vendored
@ -16,4 +16,5 @@ vendor/
|
|||||||
build/
|
build/
|
||||||
|
|
||||||
# Goland
|
# Goland
|
||||||
.idea/
|
.idea/
|
||||||
|
start.sh
|
@ -68,7 +68,7 @@ func TestValidEthTx(t *testing.T) {
|
|||||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, 22000, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
requireValidTx(t, input.anteHandler, input.ctx, tx, false)
|
requireValidTx(t, input.anteHandler, input.ctx, tx, false)
|
||||||
@ -204,7 +204,7 @@ func TestEthInvalidSig(t *testing.T) {
|
|||||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, 22000, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
ctx := input.ctx.WithChainID("4")
|
ctx := input.ctx.WithChainID("4")
|
||||||
@ -229,7 +229,7 @@ func TestEthInvalidNonce(t *testing.T) {
|
|||||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, 22000, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInvalidSequence)
|
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
@ -249,7 +249,7 @@ func TestEthInsufficientBalance(t *testing.T) {
|
|||||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, 22000, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInsufficientFunds)
|
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInsufficientFunds)
|
||||||
@ -272,7 +272,7 @@ func TestEthInvalidIntrinsicGas(t *testing.T) {
|
|||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
gasLimit := uint64(1000)
|
gasLimit := uint64(1000)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, gasLimit, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, gasLimit, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInternal)
|
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInternal)
|
||||||
@ -295,7 +295,7 @@ func TestEthInvalidMempoolFees(t *testing.T) {
|
|||||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, 22000, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInsufficientFee)
|
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInsufficientFee)
|
||||||
@ -317,7 +317,7 @@ func TestEthInvalidChainID(t *testing.T) {
|
|||||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||||
amt := big.NewInt(32)
|
amt := big.NewInt(32)
|
||||||
gas := big.NewInt(20)
|
gas := big.NewInt(20)
|
||||||
ethMsg := evmtypes.NewEthereumTxMsg(0, to, amt, 22000, gas, []byte("test"))
|
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||||
|
|
||||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||||
ctx := input.ctx.WithChainID("bad-chain-id")
|
ctx := input.ctx.WithChainID("bad-chain-id")
|
||||||
|
106
rpc/eth_api.go
106
rpc/eth_api.go
@ -9,8 +9,9 @@ import (
|
|||||||
|
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
emintkeys "github.com/cosmos/ethermint/keys"
|
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"
|
emint "github.com/cosmos/ethermint/types"
|
||||||
|
etypes "github.com/cosmos/ethermint/types"
|
||||||
"github.com/cosmos/ethermint/utils"
|
"github.com/cosmos/ethermint/utils"
|
||||||
"github.com/cosmos/ethermint/version"
|
"github.com/cosmos/ethermint/version"
|
||||||
"github.com/cosmos/ethermint/x/evm"
|
"github.com/cosmos/ethermint/x/evm"
|
||||||
@ -23,7 +24,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
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/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authutils "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
authutils "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -249,7 +248,7 @@ func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction sends an Ethereum transaction.
|
// 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
|
// 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()) {
|
if e.key == nil || !bytes.Equal(e.key.PubKey().Address().Bytes(), args.From.Bytes()) {
|
||||||
return common.Hash{}, keystore.ErrLocked
|
return common.Hash{}, keystore.ErrLocked
|
||||||
@ -262,7 +261,7 @@ func (e *PublicEthAPI) SendTransaction(args args.SendTxArgs) (common.Hash, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assemble transaction from fields
|
// Assemble transaction from fields
|
||||||
tx, err := types.GenerateFromArgs(args, e.cliCtx)
|
tx, err := e.GenerateFromArgs(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
@ -341,8 +340,14 @@ type CallArgs struct {
|
|||||||
|
|
||||||
// Call performs a raw contract call.
|
// Call performs a raw contract call.
|
||||||
func (e *PublicEthAPI) Call(args CallArgs, blockNr rpc.BlockNumber, overrides *map[common.Address]account) (hexutil.Bytes, error) {
|
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))
|
result, err := e.doCall(args, blockNr, big.NewInt(emint.DefaultRPCGasLimit))
|
||||||
return (hexutil.Bytes)(result), err
|
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
|
// 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
|
// 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
|
// Set height for historical queries
|
||||||
ctx := e.cliCtx.WithHeight(blockNr.Int64())
|
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)
|
txEncoder := authutils.GetTxEncoder(ctx.Codec)
|
||||||
txBytes, err := txEncoder(tx)
|
txBytes, err := txEncoder(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return sdk.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction simulation through query
|
// Transaction simulation through query
|
||||||
res, _, err := ctx.QueryWithData("app/simulate", txBytes)
|
res, _, err := ctx.QueryWithData("app/simulate", txBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return sdk.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var simResult sdk.Result
|
var simResult sdk.Result
|
||||||
if err = ctx.Codec.UnmarshalBinaryLengthPrefixed(res, &simResult); err != nil {
|
if err = e.cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res, &simResult); err != nil {
|
||||||
return nil, err
|
return sdk.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, ret, err := types.DecodeReturnData(simResult.Data)
|
return simResult, nil
|
||||||
|
|
||||||
return ret, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EstimateGas estimates gas usage for the given smart contract call.
|
// EstimateGas estimates gas usage for the given smart contract call.
|
||||||
func (e *PublicEthAPI) EstimateGas(args CallArgs, blockNum BlockNumber) hexutil.Uint64 {
|
func (e *PublicEthAPI) EstimateGas(args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) {
|
||||||
return 0
|
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.
|
// GetBlockByHash returns the block identified by hash.
|
||||||
@ -844,3 +852,67 @@ func (e *PublicEthAPI) getGasLimit() (int64, error) {
|
|||||||
e.gasLimit = &gasLimit
|
e.gasLimit = &gasLimit
|
||||||
return gasLimit, nil
|
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
|
||||||
|
}
|
||||||
|
@ -71,9 +71,9 @@ func GetCmdGenTx(cdc *codec.Codec) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
payload := args[4]
|
payload := args[4]
|
||||||
|
addr := ethcmn.HexToAddress(args[0])
|
||||||
// TODO: Remove explicit photon check and check variables
|
// TODO: Remove explicit photon check and check variables
|
||||||
msg := types.NewEthereumTxMsg(0, ethcmn.HexToAddress(args[0]), big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
msg := types.NewEthereumTxMsg(0, &addr, big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
||||||
err = msg.ValidateBasic()
|
err = msg.ValidateBasic()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -125,7 +125,8 @@ func GetCmdGenETHTx(cdc *codec.Codec) *cobra.Command {
|
|||||||
|
|
||||||
var tx *types.EthereumTxMsg
|
var tx *types.EthereumTxMsg
|
||||||
if len(args) == 5 {
|
if len(args) == 5 {
|
||||||
tx = types.NewEthereumTxMsg(txBldr.Sequence(), ethcmn.HexToAddress(args[4]), big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
addr := ethcmn.HexToAddress(args[4])
|
||||||
|
tx = types.NewEthereumTxMsg(txBldr.Sequence(), &addr, big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
||||||
} else {
|
} else {
|
||||||
tx = types.NewEthereumTxMsgContract(txBldr.Sequence(), big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
tx = types.NewEthereumTxMsgContract(txBldr.Sequence(), big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
||||||
"github.com/cosmos/ethermint/rpc/args"
|
|
||||||
"github.com/cosmos/ethermint/types"
|
"github.com/cosmos/ethermint/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
@ -75,11 +70,11 @@ type (
|
|||||||
|
|
||||||
// NewEthereumTxMsg returns a reference to a new Ethereum transaction message.
|
// NewEthereumTxMsg returns a reference to a new Ethereum transaction message.
|
||||||
func NewEthereumTxMsg(
|
func NewEthereumTxMsg(
|
||||||
nonce uint64, to ethcmn.Address, amount *big.Int,
|
nonce uint64, to *ethcmn.Address, amount *big.Int,
|
||||||
gasLimit uint64, gasPrice *big.Int, payload []byte,
|
gasLimit uint64, gasPrice *big.Int, payload []byte,
|
||||||
) *EthereumTxMsg {
|
) *EthereumTxMsg {
|
||||||
|
|
||||||
return newEthereumTxMsg(nonce, &to, amount, gasLimit, gasPrice, payload)
|
return newEthereumTxMsg(nonce, to, amount, gasLimit, gasPrice, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEthereumTxMsgContract returns a reference to a new Ethereum transaction
|
// NewEthereumTxMsgContract returns a reference to a new Ethereum transaction
|
||||||
@ -376,61 +371,4 @@ func recoverEthSig(R, S, Vb *big.Int, sigHash ethcmn.Hash) (ethcmn.Address, erro
|
|||||||
copy(addr[:], ethcrypto.Keccak256(pub[1:])[12:])
|
copy(addr[:], ethcrypto.Keccak256(pub[1:])[12:])
|
||||||
|
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateFromArgs populates tx message with args (used in RPC API)
|
|
||||||
func GenerateFromArgs(args args.SendTxArgs, ctx context.CLIContext) (msg *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(types.DefaultGasPrice)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.Nonce == nil {
|
|
||||||
// Get nonce (sequence) from account
|
|
||||||
from := sdk.AccAddress(args.From.Bytes())
|
|
||||||
_, nonce, err = authtypes.NewAccountRetriever(ctx).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 {
|
|
||||||
// Estimate the gas usage if necessary.
|
|
||||||
// TODO: Set gas based on estimate when simulating txs are setup
|
|
||||||
gasLimit = 60000
|
|
||||||
} else {
|
|
||||||
gasLimit = (uint64)(*args.Gas)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newEthereumTxMsg(nonce, args.To, amount, gasLimit, gasPrice, input), nil
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ import (
|
|||||||
func TestMsgEthereumTx(t *testing.T) {
|
func TestMsgEthereumTx(t *testing.T) {
|
||||||
addr := GenerateEthAddress()
|
addr := GenerateEthAddress()
|
||||||
|
|
||||||
msg1 := NewEthereumTxMsg(0, addr, nil, 100000, nil, []byte("test"))
|
msg1 := NewEthereumTxMsg(0, &addr, nil, 100000, nil, []byte("test"))
|
||||||
require.NotNil(t, msg1)
|
require.NotNil(t, msg1)
|
||||||
require.Equal(t, *msg1.Data.Recipient, addr)
|
require.Equal(t, *msg1.Data.Recipient, addr)
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ func TestMsgEthereumTx(t *testing.T) {
|
|||||||
require.NotNil(t, msg2)
|
require.NotNil(t, msg2)
|
||||||
require.Nil(t, msg2.Data.Recipient)
|
require.Nil(t, msg2.Data.Recipient)
|
||||||
|
|
||||||
msg3 := NewEthereumTxMsg(0, addr, nil, 100000, nil, []byte("test"))
|
msg3 := NewEthereumTxMsg(0, &addr, nil, 100000, nil, []byte("test"))
|
||||||
require.Equal(t, msg3.Route(), RouteEthereumTxMsg)
|
require.Equal(t, msg3.Route(), RouteEthereumTxMsg)
|
||||||
require.Equal(t, msg3.Type(), TypeEthereumTxMsg)
|
require.Equal(t, msg3.Type(), TypeEthereumTxMsg)
|
||||||
require.Panics(t, func() { msg3.GetSigners() })
|
require.Panics(t, func() { msg3.GetSigners() })
|
||||||
@ -50,7 +50,7 @@ func TestMsgEthereumTxValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
msg := NewEthereumTxMsg(tc.nonce, tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload)
|
msg := NewEthereumTxMsg(tc.nonce, &tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload)
|
||||||
|
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
require.Nil(t, msg.ValidateBasic(), "test: %v", i)
|
require.Nil(t, msg.ValidateBasic(), "test: %v", i)
|
||||||
@ -64,14 +64,14 @@ func TestMsgEthereumTxRLPSignBytes(t *testing.T) {
|
|||||||
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
||||||
chainID := big.NewInt(3)
|
chainID := big.NewInt(3)
|
||||||
|
|
||||||
msg := NewEthereumTxMsg(0, addr, nil, 100000, nil, []byte("test"))
|
msg := NewEthereumTxMsg(0, &addr, nil, 100000, nil, []byte("test"))
|
||||||
hash := msg.RLPSignBytes(chainID)
|
hash := msg.RLPSignBytes(chainID)
|
||||||
require.Equal(t, "5BD30E35AD27449390B14C91E6BCFDCAADF8FE44EF33680E3BC200FC0DC083C7", fmt.Sprintf("%X", hash))
|
require.Equal(t, "5BD30E35AD27449390B14C91E6BCFDCAADF8FE44EF33680E3BC200FC0DC083C7", fmt.Sprintf("%X", hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMsgEthereumTxRLPEncode(t *testing.T) {
|
func TestMsgEthereumTxRLPEncode(t *testing.T) {
|
||||||
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
||||||
msg := NewEthereumTxMsg(0, addr, nil, 100000, nil, []byte("test"))
|
msg := NewEthereumTxMsg(0, &addr, nil, 100000, nil, []byte("test"))
|
||||||
|
|
||||||
raw, err := rlp.EncodeToBytes(msg)
|
raw, err := rlp.EncodeToBytes(msg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -83,7 +83,7 @@ func TestMsgEthereumTxRLPDecode(t *testing.T) {
|
|||||||
|
|
||||||
raw := ethcmn.FromHex("E48080830186A0940000000000000000746573745F61646472657373808474657374808080")
|
raw := ethcmn.FromHex("E48080830186A0940000000000000000746573745F61646472657373808474657374808080")
|
||||||
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
||||||
expectedMsg := NewEthereumTxMsg(0, addr, nil, 100000, nil, []byte("test"))
|
expectedMsg := NewEthereumTxMsg(0, &addr, nil, 100000, nil, []byte("test"))
|
||||||
|
|
||||||
err := rlp.Decode(bytes.NewReader(raw), &msg)
|
err := rlp.Decode(bytes.NewReader(raw), &msg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -92,7 +92,7 @@ func TestMsgEthereumTxRLPDecode(t *testing.T) {
|
|||||||
|
|
||||||
func TestMsgEthereumTxHash(t *testing.T) {
|
func TestMsgEthereumTxHash(t *testing.T) {
|
||||||
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
addr := ethcmn.BytesToAddress([]byte("test_address"))
|
||||||
msg := NewEthereumTxMsg(0, addr, nil, 100000, nil, []byte("test"))
|
msg := NewEthereumTxMsg(0, &addr, nil, 100000, nil, []byte("test"))
|
||||||
|
|
||||||
hash := msg.Hash()
|
hash := msg.Hash()
|
||||||
require.Equal(t, "E2AA2E68E7586AE9700F1D3D643330866B6AC2B6CA4C804F7C85ECB11D0B0B29", fmt.Sprintf("%X", hash))
|
require.Equal(t, "E2AA2E68E7586AE9700F1D3D643330866B6AC2B6CA4C804F7C85ECB11D0B0B29", fmt.Sprintf("%X", hash))
|
||||||
@ -107,7 +107,7 @@ func TestMsgEthereumTxSig(t *testing.T) {
|
|||||||
addr2 := ethcmn.BytesToAddress(priv2.PubKey().Address().Bytes())
|
addr2 := ethcmn.BytesToAddress(priv2.PubKey().Address().Bytes())
|
||||||
|
|
||||||
// require valid signature passes validation
|
// require valid signature passes validation
|
||||||
msg := NewEthereumTxMsg(0, addr1, nil, 100000, nil, []byte("test"))
|
msg := NewEthereumTxMsg(0, &addr1, nil, 100000, nil, []byte("test"))
|
||||||
msg.Sign(chainID, priv1.ToECDSA())
|
msg.Sign(chainID, priv1.ToECDSA())
|
||||||
|
|
||||||
signer, err := msg.VerifySig(chainID)
|
signer, err := msg.VerifySig(chainID)
|
||||||
@ -116,7 +116,7 @@ func TestMsgEthereumTxSig(t *testing.T) {
|
|||||||
require.NotEqual(t, addr2, signer)
|
require.NotEqual(t, addr2, signer)
|
||||||
|
|
||||||
// require invalid chain ID fail validation
|
// require invalid chain ID fail validation
|
||||||
msg = NewEthereumTxMsg(0, addr1, nil, 100000, nil, []byte("test"))
|
msg = NewEthereumTxMsg(0, &addr1, nil, 100000, nil, []byte("test"))
|
||||||
msg.Sign(chainID, priv1.ToECDSA())
|
msg.Sign(chainID, priv1.ToECDSA())
|
||||||
|
|
||||||
signer, err = msg.VerifySig(big.NewInt(4))
|
signer, err = msg.VerifySig(big.NewInt(4))
|
||||||
@ -126,7 +126,7 @@ func TestMsgEthereumTxSig(t *testing.T) {
|
|||||||
|
|
||||||
func TestMsgEthereumTxAmino(t *testing.T) {
|
func TestMsgEthereumTxAmino(t *testing.T) {
|
||||||
addr := GenerateEthAddress()
|
addr := GenerateEthAddress()
|
||||||
msg := NewEthereumTxMsg(5, addr, big.NewInt(1), 100000, big.NewInt(3), []byte("test"))
|
msg := NewEthereumTxMsg(5, &addr, big.NewInt(1), 100000, big.NewInt(3), []byte("test"))
|
||||||
|
|
||||||
msg.Data.V = big.NewInt(1)
|
msg.Data.V = big.NewInt(1)
|
||||||
msg.Data.R = big.NewInt(2)
|
msg.Data.R = big.NewInt(2)
|
||||||
|
Loading…
Reference in New Issue
Block a user