upgrade changes cleanup (#236)

* changes from update version

* app changes

* cmd changes

* build and send tx

* fix tests

* eth_rpc fixes

* lint

* add WithEventManager to handler ctx

* changelog

* go mod verify and tidy
This commit is contained in:
Federico Kunze
2020-04-01 15:49:21 -03:00
committed by GitHub
parent 1627ed81bf
commit da9157e406
46 changed files with 1630 additions and 1234 deletions
+94 -55
View File
@@ -2,13 +2,15 @@ package rpc
import (
"bytes"
"errors"
"fmt"
"log"
"math/big"
"strconv"
"sync"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/spf13/viper"
emintcrypto "github.com/cosmos/ethermint/crypto"
params "github.com/cosmos/ethermint/rpc/args"
emint "github.com/cosmos/ethermint/types"
@@ -29,10 +31,10 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
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"
)
// PublicEthAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
@@ -210,7 +212,7 @@ func (e *PublicEthAPI) getBlockTransactionCountByNumber(number int64) *hexutil.U
return nil
}
n := hexutil.Uint(block.Block.NumTxs)
n := hexutil.Uint(len(block.Block.Txs))
return &n
}
@@ -277,8 +279,7 @@ func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, err
// parse the chainID from a string to a base-10 integer
intChainID, ok := new(big.Int).SetString(chainID, 10)
if !ok {
return common.Hash{}, fmt.Errorf(
fmt.Sprintf("invalid chainID: %s, must be integer format", chainID))
return common.Hash{}, fmt.Errorf("invalid chainID: %s, must be integer format", chainID)
}
// Sign transaction
@@ -306,7 +307,7 @@ func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, err
// SendRawTransaction send a raw Ethereum transaction.
func (e *PublicEthAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
tx := new(types.EthereumTxMsg)
tx := new(types.MsgEthereumTx)
// RLP decode raw transaction bytes
if err := rlp.DecodeBytes(data, tx); err != nil {
@@ -351,9 +352,12 @@ func (e *PublicEthAPI) Call(args CallArgs, blockNr rpc.BlockNumber, overrides *m
return []byte{}, err
}
_, _, ret, err := types.DecodeReturnData(result.Data)
data, err := types.DecodeResultData(result.Data)
if err != nil {
return []byte{}, err
}
return (hexutil.Bytes)(ret), err
return (hexutil.Bytes)(data.Ret), nil
}
// account indicates the overriding fields of account during the execution of
@@ -370,8 +374,9 @@ type account struct {
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
}
// DoCall performs a simulated call operation through the evm
func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasCap *big.Int) (sdk.Result, error) {
// DoCall performs a simulated call operation through the evm. It returns the
// estimated gas used on the operation or an error if fails.
func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasCap *big.Int) (*sdk.Result, error) {
// Set height for historical queries
ctx := e.cliCtx
if blockNr.Int64() != 0 {
@@ -425,7 +430,7 @@ func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasC
}
// Create new call message
msg := types.NewEmintMsg(0, &toAddr, sdk.NewIntFromBigInt(value), gas,
msg := types.NewMsgEthermint(0, &toAddr, sdk.NewIntFromBigInt(value), gas,
sdk.NewIntFromBigInt(gasPrice), data, sdk.AccAddress(addr.Bytes()))
// Generate tx to be used to simulate (signature isn't needed)
@@ -436,24 +441,26 @@ func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasC
txEncoder := authutils.GetTxEncoder(ctx.Codec)
txBytes, err := txEncoder(tx)
if err != nil {
return sdk.Result{}, err
return nil, err
}
// Transaction simulation through query
res, _, err := ctx.QueryWithData("app/simulate", txBytes)
if err != nil {
return sdk.Result{}, err
return nil, err
}
var simResult sdk.Result
if err = e.cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res, &simResult); err != nil {
return sdk.Result{}, err
return nil, err
}
return simResult, nil
return &simResult, nil
}
// EstimateGas estimates gas usage for the given smart contract call.
// EstimateGas returns an estimate of gas usage for the given smart contract call.
// It adds 1,000 gas to the returned value instead of using the gas adjustment
// param from the SDK.
func (e *PublicEthAPI) EstimateGas(args CallArgs) (hexutil.Uint64, error) {
result, err := e.doCall(args, 0, big.NewInt(emint.DefaultRPCGasLimit))
if err != nil {
@@ -482,31 +489,37 @@ func (e *PublicEthAPI) GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[
return e.getEthBlockByNumber(value, fullTx)
}
func (e *PublicEthAPI) getEthBlockByNumber(value int64, fullTx bool) (map[string]interface{}, error) {
func (e *PublicEthAPI) getEthBlockByNumber(height int64, fullTx bool) (map[string]interface{}, error) {
// Remove this check when 0 query is fixed ref: (https://github.com/tendermint/tendermint/issues/4014)
var blkNumPtr *int64
if value != 0 {
blkNumPtr = &value
if height != 0 {
blkNumPtr = &height
}
block, err := e.cliCtx.Client.Block(blkNumPtr)
if err != nil {
return nil, err
}
header := block.BlockMeta.Header
header := block.Block.Header
gasLimit, err := e.getGasLimit()
if err != nil {
return nil, err
}
var gasUsed *big.Int
var transactions []interface{}
var (
gasUsed *big.Int
transactions []interface{}
)
if fullTx {
// Populate full transaction data
transactions, gasUsed = convertTransactionsToRPC(e.cliCtx, block.Block.Txs,
common.BytesToHash(header.Hash()), uint64(header.Height))
transactions, gasUsed, err = convertTransactionsToRPC(
e.cliCtx, block.Block.Txs, common.BytesToHash(header.Hash()), uint64(header.Height),
)
if err != nil {
return nil, err
}
} else {
// TODO: Gas used not saved and cannot be calculated by hashes
// Return slice of transaction hashes
@@ -553,19 +566,24 @@ func formatBlock(
}
}
func convertTransactionsToRPC(cliCtx context.CLIContext, txs []tmtypes.Tx, blockHash common.Hash, height uint64) ([]interface{}, *big.Int) {
func convertTransactionsToRPC(cliCtx context.CLIContext, txs []tmtypes.Tx, blockHash common.Hash, height uint64) ([]interface{}, *big.Int, error) {
transactions := make([]interface{}, len(txs))
gasUsed := big.NewInt(0)
for i, tx := range txs {
ethTx, err := bytesToEthTx(cliCtx, tx)
if err != nil {
continue
return nil, nil, err
}
// TODO: Remove gas usage calculation if saving gasUsed per block
gasUsed.Add(gasUsed, ethTx.Fee())
transactions[i] = newRPCTransaction(ethTx, blockHash, &height, uint64(i))
transactions[i], err = newRPCTransaction(*ethTx, blockHash, &height, uint64(i))
if err != nil {
return nil, nil, err
}
}
return transactions, gasUsed
return transactions, gasUsed, nil
}
// Transaction represents a transaction returned to RPC clients.
@@ -586,23 +604,30 @@ type Transaction struct {
S *hexutil.Big `json:"s"`
}
func bytesToEthTx(cliCtx context.CLIContext, bz []byte) (*types.EthereumTxMsg, error) {
func bytesToEthTx(cliCtx context.CLIContext, bz []byte) (*types.MsgEthereumTx, error) {
var stdTx sdk.Tx
err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(bz, &stdTx)
ethTx, ok := stdTx.(*types.EthereumTxMsg)
if !ok || err != nil {
if err != nil {
return nil, err
}
ethTx, ok := stdTx.(types.MsgEthereumTx)
if !ok {
return nil, fmt.Errorf("invalid transaction type, must be an amino encoded Ethereum transaction")
}
return ethTx, nil
return &ethTx, nil
}
// newRPCTransaction returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
func newRPCTransaction(tx *types.EthereumTxMsg, blockHash common.Hash, blockNumber *uint64, index uint64) *Transaction {
func newRPCTransaction(tx types.MsgEthereumTx, blockHash common.Hash, blockNumber *uint64, index uint64) (*Transaction, error) {
// Verify signature and retrieve sender address
from, _ := tx.VerifySig(tx.ChainID())
from, err := tx.VerifySig(tx.ChainID())
if err != nil {
return nil, err
}
result := &Transaction{
result := Transaction{
From: from,
Gas: hexutil.Uint64(tx.Data.GasLimit),
GasPrice: (*hexutil.Big)(tx.Data.Price),
@@ -615,12 +640,14 @@ func newRPCTransaction(tx *types.EthereumTxMsg, blockHash common.Hash, blockNumb
R: (*hexutil.Big)(tx.Data.R),
S: (*hexutil.Big)(tx.Data.S),
}
if blockHash != (common.Hash{}) {
result.BlockHash = &blockHash
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(*blockNumber))
result.TransactionIndex = (*hexutil.Uint64)(&index)
}
return result
return &result, nil
}
// GetTransactionByHash returns the transaction identified by hash.
@@ -636,7 +663,7 @@ func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*Transaction, err
if err != nil {
return nil, err
}
blockHash := common.BytesToHash(block.BlockMeta.Header.Hash())
blockHash := common.BytesToHash(block.Block.Header.Hash())
ethTx, err := bytesToEthTx(e.cliCtx, tx.Tx)
if err != nil {
@@ -644,7 +671,7 @@ func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*Transaction, err
}
height := uint64(tx.Height)
return newRPCTransaction(ethTx, blockHash, &height, uint64(tx.Index)), nil
return newRPCTransaction(*ethTx, blockHash, &height, uint64(tx.Index))
}
// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
@@ -670,7 +697,7 @@ func (e *PublicEthAPI) getTransactionByBlockNumberAndIndex(number int64, idx hex
if err != nil {
return nil, err
}
header := block.BlockMeta.Header
header := block.Block.Header
txs := block.Block.Txs
if uint64(idx) >= uint64(len(txs)) {
@@ -682,8 +709,7 @@ func (e *PublicEthAPI) getTransactionByBlockNumberAndIndex(number int64, idx hex
}
height := uint64(header.Height)
transaction := newRPCTransaction(ethTx, common.BytesToHash(header.Hash()), &height, uint64(idx))
return transaction, nil
return newRPCTransaction(*ethTx, common.BytesToHash(header.Hash()), &height, uint64(idx))
}
// GetTransactionReceipt returns the transaction receipt identified by hash.
@@ -699,7 +725,7 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
if err != nil {
return nil, err
}
blockHash := common.BytesToHash(block.BlockMeta.Header.Hash())
blockHash := common.BytesToHash(block.Block.Header.Hash())
// Convert tx bytes to eth transaction
ethTx, err := bytesToEthTx(e.cliCtx, tx.Tx)
@@ -726,7 +752,10 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
e.cliCtx.Codec.MustUnmarshalJSON(res, &logs)
txData := tx.TxResult.GetData()
contractAddress, bloomFilter, _, _ := types.DecodeReturnData(txData)
data, err := types.DecodeResultData(txData)
if err != nil {
return nil, err
}
fields := map[string]interface{}{
"blockHash": blockHash,
@@ -739,12 +768,12 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
"cumulativeGasUsed": nil, // ignore until needed
"contractAddress": nil,
"logs": logs.Logs,
"logsBloom": bloomFilter,
"logsBloom": data.Bloom,
"status": status,
}
if contractAddress != (common.Address{}) {
fields["contractAddress"] = contractAddress
if data.Address != (common.Address{}) {
fields["contractAddress"] = data.Address
}
return fields, nil
@@ -766,7 +795,11 @@ func (e *PublicEthAPI) PendingTransactions() ([]*Transaction, error) {
}
// * Should check signer and reference against accounts the node manages in future
rpcTx := newRPCTransaction(ethTx, common.Hash{}, nil, 0)
rpcTx, err := newRPCTransaction(*ethTx, common.Hash{}, nil, 0)
if err != nil {
return nil, err
}
transactions = append(transactions, rpcTx)
}
@@ -871,13 +904,14 @@ func (e *PublicEthAPI) getGasLimit() (int64, error) {
}
// 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
func (e *PublicEthAPI) generateFromArgs(args params.SendTxArgs) (*types.MsgEthereumTx, error) {
var (
nonce uint64
gasLimit uint64
err error
)
amount := (*big.Int)(args.Value)
gasPrice := (*big.Int)(args.GasPrice)
if args.GasPrice == nil {
@@ -899,7 +933,7 @@ func (e *PublicEthAPI) generateFromArgs(args params.SendTxArgs) (msg *types.Ethe
}
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`)
return nil, errors.New(`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
@@ -916,6 +950,7 @@ func (e *PublicEthAPI) generateFromArgs(args params.SendTxArgs) (msg *types.Ethe
return nil, fmt.Errorf("contract creation without any data provided")
}
}
if args.Gas == nil {
callArgs := CallArgs{
From: &args.From,
@@ -925,11 +960,15 @@ func (e *PublicEthAPI) generateFromArgs(args params.SendTxArgs) (msg *types.Ethe
Value: args.Value,
Data: args.Data,
}
g, _ := e.EstimateGas(callArgs)
g, err := e.EstimateGas(callArgs)
if err != nil {
return nil, err
}
gasLimit = uint64(g)
} else {
gasLimit = (uint64)(*args.Gas)
}
msg := types.NewMsgEthereumTx(nonce, args.To, amount, gasLimit, gasPrice, input)
return types.NewEthereumTxMsg(nonce, args.To, amount, gasLimit, gasPrice, input), nil
return &msg, nil
}
+15 -44
View File
@@ -18,6 +18,7 @@ import (
"github.com/cosmos/ethermint/version"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
)
const (
@@ -92,51 +93,34 @@ func TestEth_protocolVersion(t *testing.T) {
expectedRes := hexutil.Uint(version.ProtocolVersion)
rpcRes, err := call("eth_protocolVersion", []string{})
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
var res hexutil.Uint
err = res.UnmarshalJSON(rpcRes.Result)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
t.Logf("Got protocol version: %s\n", res.String())
if res != expectedRes {
t.Fatalf("expected: %s got: %s\n", expectedRes.String(), rpcRes.Result)
}
require.Equal(t, expectedRes, res, "expected: %s got: %s\n", expectedRes.String(), rpcRes.Result)
}
func TestEth_blockNumber(t *testing.T) {
rpcRes, err := call("eth_blockNumber", []string{})
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
var res hexutil.Uint64
err = res.UnmarshalJSON(rpcRes.Result)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
t.Logf("Got block number: %s\n", res.String())
}
func TestEth_GetBalance(t *testing.T) {
rpcRes, err := call("eth_getBalance", []string{addrA, "0x0"})
if err != nil {
t.Fatal(err)
return
}
require.NoError(t, err)
var res hexutil.Big
err = res.UnmarshalJSON(rpcRes.Result)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
t.Logf("Got balance %s for %s\n", res.String(), addrA)
@@ -149,40 +133,27 @@ func TestEth_GetBalance(t *testing.T) {
func TestEth_GetStorageAt(t *testing.T) {
expectedRes := hexutil.Bytes{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
rpcRes, err := call("eth_getStorageAt", []string{addrA, string(addrAStoreKey), "0x0"})
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
var storage hexutil.Bytes
err = storage.UnmarshalJSON(rpcRes.Result)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
t.Logf("Got value [%X] for %s with key %X\n", storage, addrA, addrAStoreKey)
if !bytes.Equal(storage, expectedRes) {
t.Errorf("expected: %d (%d bytes) got: %d (%d bytes)", expectedRes, len(expectedRes), storage, len(storage))
}
require.True(t, bytes.Equal(storage, expectedRes), "expected: %d (%d bytes) got: %d (%d bytes)", expectedRes, len(expectedRes), storage, len(storage))
}
func TestEth_GetCode(t *testing.T) {
expectedRes := hexutil.Bytes{}
rpcRes, err := call("eth_getCode", []string{addrA, "0x0"})
if err != nil {
t.Error(err)
}
require.NoError(t, err)
var code hexutil.Bytes
err = code.UnmarshalJSON(rpcRes.Result)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
t.Logf("Got code [%X] for %s\n", code, addrA)
if !bytes.Equal(expectedRes, code) {
t.Errorf("expected: %X got: %X", expectedRes, code)
}
require.True(t, bytes.Equal(expectedRes, code), "expected: %X got: %X", expectedRes, code)
}