Skip to content
This repository was archived by the owner on Nov 30, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions rpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"bytes"
"errors"
"fmt"
"log"
"math/big"
"os"
"strconv"
"sync"

Expand All @@ -20,6 +20,7 @@ import (

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/rpc/client"
tmtypes "github.com/tendermint/tendermint/types"

Expand All @@ -42,6 +43,7 @@ import (
// PublicEthAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicEthAPI struct {
cliCtx context.CLIContext
logger log.Logger
backend Backend
keys []crypto.PrivKeySecp256k1
nonceLock *AddrLocker
Expand All @@ -54,6 +56,7 @@ func NewPublicEthAPI(cliCtx context.CLIContext, backend Backend, nonceLock *Addr

return &PublicEthAPI{
cliCtx: cliCtx,
logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "json-rpc"),
backend: backend,
keys: key,
nonceLock: nonceLock,
Expand All @@ -62,11 +65,14 @@ func NewPublicEthAPI(cliCtx context.CLIContext, backend Backend, nonceLock *Addr

// ProtocolVersion returns the supported Ethereum protocol version.
func (e *PublicEthAPI) ProtocolVersion() hexutil.Uint {
e.logger.Debug("eth_protocolVersion")
return hexutil.Uint(version.ProtocolVersion)
}

// ChainId returns the chain's identifier in hex format
func (e *PublicEthAPI) ChainId() (hexutil.Uint, error) { // nolint
e.logger.Debug("eth_chainId")

// parse the chainID from a integer string
intChainID, err := strconv.ParseUint(e.cliCtx.ChainID, 0, 64)
if err != nil {
Expand All @@ -79,6 +85,8 @@ func (e *PublicEthAPI) ChainId() (hexutil.Uint, error) { // nolint
// Syncing returns whether or not the current node is syncing with other peers. Returns false if not, or a struct
// outlining the state of the sync if it is.
func (e *PublicEthAPI) Syncing() (interface{}, error) {
e.logger.Debug("eth_syncing")

status, err := e.cliCtx.Client.Status()
if err != nil {
return false, err
Expand All @@ -99,6 +107,8 @@ func (e *PublicEthAPI) Syncing() (interface{}, error) {

// Coinbase is the address that staking rewards will be send to (alias for Etherbase).
func (e *PublicEthAPI) Coinbase() (common.Address, error) {
e.logger.Debug("eth_coinbase")

node, err := e.cliCtx.GetNode()
if err != nil {
return common.Address{}, err
Expand All @@ -114,22 +124,26 @@ func (e *PublicEthAPI) Coinbase() (common.Address, error) {

// Mining returns whether or not this node is currently mining. Always false.
func (e *PublicEthAPI) Mining() bool {
e.logger.Debug("eth_mining")
return false
}

// Hashrate returns the current node's hashrate. Always 0.
func (e *PublicEthAPI) Hashrate() hexutil.Uint64 {
e.logger.Debug("eth_hashrate")
return 0
}

// GasPrice returns the current gas price based on Ethermint's gas price oracle.
func (e *PublicEthAPI) GasPrice() *hexutil.Big {
e.logger.Debug("eth_gasPrice")
out := big.NewInt(0)
return (*hexutil.Big)(out)
}

// Accounts returns the list of accounts available to this node.
func (e *PublicEthAPI) Accounts() ([]common.Address, error) {
e.logger.Debug("eth_accounts")
e.keybaseLock.Lock()

addresses := make([]common.Address, 0) // return [] instead of nil if empty
Expand Down Expand Up @@ -162,11 +176,13 @@ func (e *PublicEthAPI) Accounts() ([]common.Address, error) {

// BlockNumber returns the current block number.
func (e *PublicEthAPI) BlockNumber() (hexutil.Uint64, error) {
e.logger.Debug("eth_blockNumber")
return e.backend.BlockNumber()
}

// GetBalance returns the provided account's balance up to the provided block number.
func (e *PublicEthAPI) GetBalance(address common.Address, blockNum BlockNumber) (*hexutil.Big, error) {
e.logger.Debug("eth_getBalance", "address", address, "block number", blockNum)
ctx := e.cliCtx.WithHeight(blockNum.Int64())
res, _, err := ctx.QueryWithData(fmt.Sprintf("custom/%s/balance/%s", evmtypes.ModuleName, address.Hex()), nil)
if err != nil {
Expand All @@ -185,6 +201,7 @@ func (e *PublicEthAPI) GetBalance(address common.Address, blockNum BlockNumber)

// GetStorageAt returns the contract storage at the given address, block number, and key.
func (e *PublicEthAPI) GetStorageAt(address common.Address, key string, blockNum BlockNumber) (hexutil.Bytes, error) {
e.logger.Debug("eth_getStorageAt", "address", address, "key", key, "block number", blockNum)
ctx := e.cliCtx.WithHeight(blockNum.Int64())
res, _, err := ctx.QueryWithData(fmt.Sprintf("custom/%s/storage/%s/%s", evmtypes.ModuleName, address.Hex(), key), nil)
if err != nil {
Expand All @@ -198,6 +215,7 @@ func (e *PublicEthAPI) GetStorageAt(address common.Address, key string, blockNum

// GetTransactionCount returns the number of transactions at the given address up to the given block number.
func (e *PublicEthAPI) GetTransactionCount(address common.Address, blockNum BlockNumber) (*hexutil.Uint64, error) {
e.logger.Debug("eth_getTransactionCount", "address", address, "block number", blockNum)
ctx := e.cliCtx.WithHeight(blockNum.Int64())

// Get nonce (sequence) from account
Expand All @@ -222,6 +240,7 @@ func (e *PublicEthAPI) GetTransactionCount(address common.Address, blockNum Bloc

// GetBlockTransactionCountByHash returns the number of transactions in the block identified by hash.
func (e *PublicEthAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
e.logger.Debug("eth_getBlockTransactionCountByHash", "hash", hash)
res, _, err := e.cliCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex()))
if err != nil {
// Return nil if block does not exist
Expand All @@ -235,6 +254,7 @@ func (e *PublicEthAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil

// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number.
func (e *PublicEthAPI) GetBlockTransactionCountByNumber(blockNum BlockNumber) *hexutil.Uint {
e.logger.Debug("eth_getBlockTransactionCountByNumber", "block number", blockNum)
height := blockNum.Int64()
return e.getBlockTransactionCountByNumber(height)
}
Expand Down Expand Up @@ -262,6 +282,7 @@ func (e *PublicEthAPI) GetUncleCountByBlockNumber(blockNum BlockNumber) hexutil.

// GetCode returns the contract code at the given address and block number.
func (e *PublicEthAPI) GetCode(address common.Address, blockNumber BlockNumber) (hexutil.Bytes, error) {
e.logger.Debug("eth_getCode", "address", address, "block number", blockNumber)
ctx := e.cliCtx.WithHeight(blockNumber.Int64())
res, _, err := ctx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryCode, address.Hex()), nil)
if err != nil {
Expand All @@ -275,12 +296,14 @@ func (e *PublicEthAPI) GetCode(address common.Address, blockNumber BlockNumber)

// GetTransactionLogs returns the logs given a transaction hash.
func (e *PublicEthAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
e.logger.Debug("eth_getTransactionLogs", "hash", txHash)
return e.backend.GetTransactionLogs(txHash)
}

// ExportAccount exports an account's balance, code, and storage at the given block number
// TODO: deprecate this once the export genesis command works
func (e *PublicEthAPI) ExportAccount(address common.Address, blockNumber BlockNumber) (string, error) {
e.logger.Debug("eth_exportAccount", "address", address, "block number", blockNumber)
ctx := e.cliCtx.WithHeight(blockNumber.Int64())

res, _, err := ctx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryExportAccount, address.Hex()), nil)
Expand All @@ -304,6 +327,7 @@ func checkKeyInKeyring(keys []crypto.PrivKeySecp256k1, address common.Address) (

// Sign signs the provided data using the private key of address via Geth's signature standard.
func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
e.logger.Debug("eth_sign", "address", address, "data", data)
// TODO: Change this functionality to find an unlocked account by address

key, exist := checkKeyInKeyring(e.keys, address)
Expand All @@ -322,6 +346,7 @@ func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil

// SendTransaction sends an Ethereum transaction.
func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, error) {
e.logger.Debug("eth_sendTransaction", "args", args)
// TODO: Change this functionality to find an unlocked account by address

key, exist := checkKeyInKeyring(e.keys, args.From)
Expand Down Expand Up @@ -374,6 +399,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) {
e.logger.Debug("eth_sendRawTransaction", "data", data)
tx := new(evmtypes.MsgEthereumTx)

// RLP decode raw transaction bytes
Expand Down Expand Up @@ -411,7 +437,8 @@ type CallArgs struct {
}

// Call performs a raw contract call.
func (e *PublicEthAPI) Call(args CallArgs, blockNr BlockNumber, overrides *map[common.Address]account) (hexutil.Bytes, error) {
func (e *PublicEthAPI) Call(args CallArgs, blockNr BlockNumber, _ *map[common.Address]account) (hexutil.Bytes, error) {
e.logger.Debug("eth_call", "args", args, "block number", blockNr)
simRes, err := e.doCall(args, blockNr, big.NewInt(emint.DefaultRPCGasLimit))
if err != nil {
return []byte{}, err
Expand Down Expand Up @@ -471,7 +498,7 @@ func (e *PublicEthAPI) doCall(
gas = uint64(*args.Gas)
}
if globalGasCap != nil && globalGasCap.Uint64() < gas {
log.Println("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
e.logger.Debug("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
gas = globalGasCap.Uint64()
}

Expand Down Expand Up @@ -531,6 +558,7 @@ func (e *PublicEthAPI) doCall(
// 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) {
e.logger.Debug("eth_estimateGas", "args", args)
simResponse, err := e.doCall(args, 0, big.NewInt(emint.DefaultRPCGasLimit))
if err != nil {
return 0, err
Expand All @@ -545,11 +573,13 @@ func (e *PublicEthAPI) EstimateGas(args CallArgs) (hexutil.Uint64, error) {

// GetBlockByHash returns the block identified by hash.
func (e *PublicEthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
e.logger.Debug("eth_getBlockByHash", "hash", hash, "full", fullTx)
return e.backend.GetBlockByHash(hash, fullTx)
}

// GetBlockByNumber returns the block identified by number.
func (e *PublicEthAPI) GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[string]interface{}, error) {
e.logger.Debug("eth_getBlockByNumber", "number", blockNum, "full", fullTx)
return e.backend.GetBlockByNumber(blockNum, fullTx)
}

Expand Down Expand Up @@ -668,6 +698,7 @@ func newRPCTransaction(tx evmtypes.MsgEthereumTx, txHash, blockHash common.Hash,

// GetTransactionByHash returns the transaction identified by hash.
func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*Transaction, error) {
e.logger.Debug("eth_getTransactionByHash", "hash", hash)
tx, err := e.cliCtx.Client.Tx(hash.Bytes(), false)
if err != nil {
// Return nil for transaction when not found
Expand All @@ -692,6 +723,7 @@ func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*Transaction, err

// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
func (e *PublicEthAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*Transaction, error) {
e.logger.Debug("eth_getTransactionByHashAndIndex", "hash", hash, "index", idx)
res, _, err := e.cliCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex()))
if err != nil {
return nil, err
Expand All @@ -704,6 +736,7 @@ func (e *PublicEthAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx h

// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
func (e *PublicEthAPI) GetTransactionByBlockNumberAndIndex(blockNum BlockNumber, idx hexutil.Uint) (*Transaction, error) {
e.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
value := blockNum.Int64()
return e.getTransactionByBlockNumberAndIndex(value, idx)
}
Expand All @@ -730,6 +763,7 @@ func (e *PublicEthAPI) getTransactionByBlockNumberAndIndex(number int64, idx hex

// GetTransactionReceipt returns the transaction receipt identified by hash.
func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
e.logger.Debug("eth_getTransactionReceipt", "hash", hash)
tx, err := e.cliCtx.Client.Tx(hash.Bytes(), false)
if err != nil {
// Return nil for transaction when not found
Expand Down Expand Up @@ -803,6 +837,7 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
// PendingTransactions returns the transactions that are in the transaction pool
// and have a from address that is one of the accounts this node manages.
func (e *PublicEthAPI) PendingTransactions() ([]*Transaction, error) {
e.logger.Debug("eth_getPendingTransactions")
return e.backend.PendingTransactions()
}

Expand Down Expand Up @@ -839,6 +874,7 @@ type StorageResult struct {

// GetProof returns an account object with proof and any storage proofs
func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, block BlockNumber) (*AccountResult, error) {
e.logger.Debug("eth_getProof", "address", address, "keys", storageKeys, "number", block)
e.cliCtx = e.cliCtx.WithHeight(int64(block))
path := fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryAccount, address.Hex())

Expand Down
7 changes: 4 additions & 3 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@ func (k Keeper) SetBlockHash(ctx sdk.Context, hash []byte, height int64) {
// GetBlockBloom gets bloombits from block height
func (k Keeper) GetBlockBloom(ctx sdk.Context, height int64) (ethtypes.Bloom, bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixBloom)
bz := store.Get(types.BloomKey(height))
if len(bz) == 0 {
return ethtypes.Bloom{}, false
has := store.Has(types.BloomKey(height))
if !has {
return ethtypes.Bloom{}, true // TODO: sometimes bloom cannot be found, fix this
}

bz := store.Get(types.BloomKey(height))
return ethtypes.BytesToBloom(bz), true
}

Expand Down