77ed4aa754
* Store eth tx index separately Closes: #1075 Solution: - run a optional indexer service - adapt the json-rpc to the more efficient query changelog changelog fix lint fix backward compatibility fix lint timeout better strconv fix linter fix package name add cli command to index old tx fix for loop indexer cmd don't have access to local rpc workaround exceed block gas limit situation add unit tests for indexer refactor polish the indexer module Update server/config/toml.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> improve comments share code between GetTxByEthHash and GetTxByIndex fix unit test Update server/indexer.go Co-authored-by: Freddy Caceres <facs95@gmail.com> * Apply suggestions from code review * test enable-indexer in integration test * fix go lint * address review suggestions * fix linter * address review suggestions - test indexer in backend unit test - add comments * fix build * fix test * service name Co-authored-by: Freddy Caceres <facs95@gmail.com> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
543 lines
22 KiB
Go
543 lines
22 KiB
Go
package eth
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
|
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
|
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
|
|
"github.com/evmos/ethermint/rpc/backend"
|
|
|
|
rpctypes "github.com/evmos/ethermint/rpc/types"
|
|
ethermint "github.com/evmos/ethermint/types"
|
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
|
)
|
|
|
|
// The Ethereum API allows applications to connect to an Evmos node that is
|
|
// part of the Evmos blockchain. Developers can interact with on-chain EVM data
|
|
// and send different types of transactions to the network by utilizing the
|
|
// endpoints provided by the API. The API follows a JSON-RPC standard. If not
|
|
// otherwise specified, the interface is derived from the Alchemy Ethereum API:
|
|
// https://docs.alchemy.com/alchemy/apis/ethereum
|
|
type EthereumAPI interface {
|
|
// Getting Blocks
|
|
//
|
|
// Retrieves information from a particular block in the blockchain.
|
|
BlockNumber() (hexutil.Uint64, error)
|
|
GetBlockByNumber(ethBlockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error)
|
|
GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error)
|
|
|
|
// Reading Transactions
|
|
//
|
|
// Retrieves information on the state data for addresses regardless of whether
|
|
// it is a user or a smart contract.
|
|
GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error)
|
|
GetTransactionCount(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Uint64, error)
|
|
GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error)
|
|
GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint
|
|
GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint
|
|
GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error)
|
|
GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error)
|
|
// eth_getBlockReceipts
|
|
|
|
// Writing Transactions
|
|
//
|
|
// Allows developers to both send ETH from one address to another, write data
|
|
// on-chain, and interact with smart contracts.
|
|
SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
|
|
SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error)
|
|
// eth_sendPrivateTransaction
|
|
// eth_cancel PrivateTransaction
|
|
|
|
// Account Information
|
|
//
|
|
// Returns information regarding an address's stored on-chain data.
|
|
Accounts() ([]common.Address, error)
|
|
GetBalance(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Big, error)
|
|
GetStorageAt(address common.Address, key string, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error)
|
|
GetCode(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error)
|
|
GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error)
|
|
|
|
// EVM/Smart Contract Execution
|
|
//
|
|
// Allows developers to read data from the blockchain which includes executing
|
|
// smart contracts. However, no data is published to the Ethereum network.
|
|
Call(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash, _ *rpctypes.StateOverride) (hexutil.Bytes, error)
|
|
|
|
// Chain Information
|
|
//
|
|
// Returns information on the Ethereum network and internal settings.
|
|
ProtocolVersion() hexutil.Uint
|
|
GasPrice() (*hexutil.Big, error)
|
|
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rpctypes.BlockNumber) (hexutil.Uint64, error)
|
|
FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpctypes.FeeHistoryResult, error)
|
|
MaxPriorityFeePerGas() (*hexutil.Big, error)
|
|
ChainId() (*hexutil.Big, error)
|
|
|
|
// Getting Uncles
|
|
//
|
|
// Returns information on uncle blocks are which are network rejected blocks and replaced by a canonical block instead.
|
|
GetUncleByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) map[string]interface{}
|
|
GetUncleByBlockNumberAndIndex(number, idx hexutil.Uint) map[string]interface{}
|
|
GetUncleCountByBlockHash(hash common.Hash) hexutil.Uint
|
|
GetUncleCountByBlockNumber(blockNum rpctypes.BlockNumber) hexutil.Uint
|
|
|
|
// Proof of Work
|
|
Hashrate() hexutil.Uint64
|
|
Mining() bool
|
|
|
|
// Other
|
|
Syncing() (interface{}, error)
|
|
Coinbase() (string, error)
|
|
Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error)
|
|
GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error)
|
|
SignTypedData(address common.Address, typedData apitypes.TypedData) (hexutil.Bytes, error)
|
|
FillTransaction(args evmtypes.TransactionArgs) (*rpctypes.SignTransactionResult, error)
|
|
Resend(ctx context.Context, args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error)
|
|
GetPendingTransactions() ([]*rpctypes.RPCTransaction, error)
|
|
// eth_signTransaction (on Ethereum.org)
|
|
// eth_getCompilers (on Ethereum.org)
|
|
// eth_compileSolidity (on Ethereum.org)
|
|
// eth_compileLLL (on Ethereum.org)
|
|
// eth_compileSerpent (on Ethereum.org)
|
|
// eth_getWork (on Ethereum.org)
|
|
// eth_submitWork (on Ethereum.org)
|
|
// eth_submitHashrate (on Ethereum.org)
|
|
}
|
|
|
|
var _ EthereumAPI = (*PublicAPI)(nil)
|
|
|
|
// PublicAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
|
type PublicAPI struct {
|
|
ctx context.Context
|
|
logger log.Logger
|
|
backend backend.EVMBackend
|
|
}
|
|
|
|
// NewPublicAPI creates an instance of the public ETH Web3 API.
|
|
func NewPublicAPI(
|
|
logger log.Logger,
|
|
backend backend.EVMBackend,
|
|
) *PublicAPI {
|
|
api := &PublicAPI{
|
|
ctx: context.Background(),
|
|
logger: logger.With("client", "json-rpc"),
|
|
backend: backend,
|
|
}
|
|
|
|
return api
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Blocks ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// BlockNumber returns the current block number.
|
|
func (e *PublicAPI) BlockNumber() (hexutil.Uint64, error) {
|
|
e.logger.Debug("eth_blockNumber")
|
|
return e.backend.BlockNumber()
|
|
}
|
|
|
|
// GetBlockByNumber returns the block identified by number.
|
|
func (e *PublicAPI) GetBlockByNumber(ethBlockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
|
e.logger.Debug("eth_getBlockByNumber", "number", ethBlockNum, "full", fullTx)
|
|
return e.backend.GetBlockByNumber(ethBlockNum, fullTx)
|
|
}
|
|
|
|
// GetBlockByHash returns the block identified by hash.
|
|
func (e *PublicAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
|
e.logger.Debug("eth_getBlockByHash", "hash", hash.Hex(), "full", fullTx)
|
|
return e.backend.GetBlockByHash(hash, fullTx)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Read Txs ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetTransactionByHash returns the transaction identified by hash.
|
|
func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) {
|
|
e.logger.Debug("eth_getTransactionByHash", "hash", hash.Hex())
|
|
return e.backend.GetTransactionByHash(hash)
|
|
}
|
|
|
|
// GetTransactionCount returns the number of transactions at the given address up to the given block number.
|
|
func (e *PublicAPI) GetTransactionCount(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Uint64, error) {
|
|
e.logger.Debug("eth_getTransactionCount", "address", address.Hex(), "block number or hash", blockNrOrHash)
|
|
blockNum, err := e.backend.GetBlockNumber(blockNrOrHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return e.backend.GetTransactionCount(address, blockNum)
|
|
}
|
|
|
|
// GetTransactionReceipt returns the transaction receipt identified by hash.
|
|
func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
|
|
hexTx := hash.Hex()
|
|
e.logger.Debug("eth_getTransactionReceipt", "hash", hexTx)
|
|
|
|
return e.backend.GetTransactionReceipt(hash)
|
|
}
|
|
|
|
// GetBlockTransactionCountByHash returns the number of transactions in the block identified by hash.
|
|
func (e *PublicAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
|
|
e.logger.Debug("eth_getBlockTransactionCountByHash", "hash", hash.Hex())
|
|
|
|
return e.backend.GetBlockTransactionCountByHash(hash)
|
|
}
|
|
|
|
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number.
|
|
func (e *PublicAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint {
|
|
e.logger.Debug("eth_getBlockTransactionCountByNumber", "height", blockNum.Int64())
|
|
|
|
return e.backend.GetBlockTransactionCountByNumber(blockNum)
|
|
}
|
|
|
|
// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
|
|
func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
|
e.logger.Debug("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx)
|
|
return e.backend.GetTransactionByBlockHashAndIndex(hash, idx)
|
|
}
|
|
|
|
// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
|
|
func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
|
e.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
|
|
|
|
block, err := e.backend.GetTendermintBlockByNumber(blockNum)
|
|
if err != nil {
|
|
e.logger.Debug("block not found", "height", blockNum.Int64(), "error", err.Error())
|
|
return nil, nil
|
|
}
|
|
|
|
if block.Block == nil {
|
|
e.logger.Debug("block not found", "height", blockNum.Int64())
|
|
return nil, nil
|
|
}
|
|
|
|
return e.backend.GetTransactionByBlockAndIndex(block, idx)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Write Txs ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SendRawTransaction send a raw Ethereum transaction.
|
|
func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
|
|
e.logger.Debug("eth_sendRawTransaction", "length", len(data))
|
|
return e.backend.SendRawTransaction(data)
|
|
}
|
|
|
|
// SendTransaction sends an Ethereum transaction.
|
|
func (e *PublicAPI) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) {
|
|
e.logger.Debug("eth_sendTransaction", "args", args.String())
|
|
return e.backend.SendTransaction(args)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Account Information ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Accounts returns the list of accounts available to this node.
|
|
func (e *PublicAPI) Accounts() ([]common.Address, error) {
|
|
e.logger.Debug("eth_accounts")
|
|
return e.backend.Accounts()
|
|
}
|
|
|
|
// GetBalance returns the provided account's balance up to the provided block number.
|
|
func (e *PublicAPI) GetBalance(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Big, error) {
|
|
e.logger.Debug("eth_getBalance", "address", address.String(), "block number or hash", blockNrOrHash)
|
|
return e.backend.GetBalance(address, blockNrOrHash)
|
|
}
|
|
|
|
// GetStorageAt returns the contract storage at the given address, block number, and key.
|
|
func (e *PublicAPI) GetStorageAt(address common.Address, key string, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) {
|
|
e.logger.Debug("eth_getStorageAt", "address", address.Hex(), "key", key, "block number or hash", blockNrOrHash)
|
|
return e.backend.GetStorageAt(address, key, blockNrOrHash)
|
|
}
|
|
|
|
// GetCode returns the contract code at the given address and block number.
|
|
func (e *PublicAPI) GetCode(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) {
|
|
e.logger.Debug("eth_getCode", "address", address.Hex(), "block number or hash", blockNrOrHash)
|
|
return e.backend.GetCode(address, blockNrOrHash)
|
|
}
|
|
|
|
// GetProof returns an account object with proof and any storage proofs
|
|
func (e *PublicAPI) GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) {
|
|
e.logger.Debug("eth_getProof", "address", address.Hex(), "keys", storageKeys, "block number or hash", blockNrOrHash)
|
|
return e.backend.GetProof(address, storageKeys, blockNrOrHash)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// EVM/Smart Contract Execution ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Call performs a raw contract call.
|
|
func (e *PublicAPI) Call(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash, _ *rpctypes.StateOverride) (hexutil.Bytes, error) {
|
|
e.logger.Debug("eth_call", "args", args.String(), "block number or hash", blockNrOrHash)
|
|
|
|
blockNum, err := e.backend.GetBlockNumber(blockNrOrHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data, err := e.backend.DoCall(args, blockNum)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
return (hexutil.Bytes)(data.Ret), nil
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Event Logs ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FILTER API
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Chain Information ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ProtocolVersion returns the supported Ethereum protocol version.
|
|
func (e *PublicAPI) ProtocolVersion() hexutil.Uint {
|
|
e.logger.Debug("eth_protocolVersion")
|
|
return hexutil.Uint(ethermint.ProtocolVersion)
|
|
}
|
|
|
|
// GasPrice returns the current gas price based on Ethermint's gas price oracle.
|
|
func (e *PublicAPI) GasPrice() (*hexutil.Big, error) {
|
|
e.logger.Debug("eth_gasPrice")
|
|
var (
|
|
result *big.Int
|
|
err error
|
|
)
|
|
if head := e.backend.CurrentHeader(); head.BaseFee != nil {
|
|
result, err = e.backend.SuggestGasTipCap(head.BaseFee)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result = result.Add(result, head.BaseFee)
|
|
} else {
|
|
result = big.NewInt(e.backend.RPCMinGasPrice())
|
|
}
|
|
|
|
// return at least GlobalMinGasPrice from FeeMarket module
|
|
minGasPrice, err := e.backend.GlobalMinGasPrice()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
minGasPriceInt := minGasPrice.TruncateInt().BigInt()
|
|
if result.Cmp(minGasPriceInt) < 0 {
|
|
result = minGasPriceInt
|
|
}
|
|
|
|
return (*hexutil.Big)(result), nil
|
|
}
|
|
|
|
// EstimateGas returns an estimate of gas usage for the given smart contract call.
|
|
func (e *PublicAPI) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rpctypes.BlockNumber) (hexutil.Uint64, error) {
|
|
e.logger.Debug("eth_estimateGas")
|
|
return e.backend.EstimateGas(args, blockNrOptional)
|
|
}
|
|
|
|
func (e *PublicAPI) FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpctypes.FeeHistoryResult, error) {
|
|
e.logger.Debug("eth_feeHistory")
|
|
return e.backend.FeeHistory(blockCount, lastBlock, rewardPercentiles)
|
|
}
|
|
|
|
// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions.
|
|
func (e *PublicAPI) MaxPriorityFeePerGas() (*hexutil.Big, error) {
|
|
e.logger.Debug("eth_maxPriorityFeePerGas")
|
|
head := e.backend.CurrentHeader()
|
|
tipcap, err := e.backend.SuggestGasTipCap(head.BaseFee)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return (*hexutil.Big)(tipcap), nil
|
|
}
|
|
|
|
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
|
|
func (e *PublicAPI) ChainId() (*hexutil.Big, error) { //nolint
|
|
e.logger.Debug("eth_chainId")
|
|
return e.backend.ChainID()
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Uncles ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil.
|
|
func (e *PublicAPI) GetUncleByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) map[string]interface{} {
|
|
return nil
|
|
}
|
|
|
|
// GetUncleByBlockNumberAndIndex returns the uncle identified by number and index. Always returns nil.
|
|
func (e *PublicAPI) GetUncleByBlockNumberAndIndex(number, idx hexutil.Uint) map[string]interface{} {
|
|
return nil
|
|
}
|
|
|
|
// GetUncleCountByBlockHash returns the number of uncles in the block identified by hash. Always zero.
|
|
func (e *PublicAPI) GetUncleCountByBlockHash(hash common.Hash) hexutil.Uint {
|
|
return 0
|
|
}
|
|
|
|
// GetUncleCountByBlockNumber returns the number of uncles in the block identified by number. Always zero.
|
|
func (e *PublicAPI) GetUncleCountByBlockNumber(blockNum rpctypes.BlockNumber) hexutil.Uint {
|
|
return 0
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Proof of Work ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Hashrate returns the current node's hashrate. Always 0.
|
|
func (e *PublicAPI) Hashrate() hexutil.Uint64 {
|
|
e.logger.Debug("eth_hashrate")
|
|
return 0
|
|
}
|
|
|
|
// Mining returns whether or not this node is currently mining. Always false.
|
|
func (e *PublicAPI) Mining() bool {
|
|
e.logger.Debug("eth_mining")
|
|
return false
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Other ///
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
|
|
// yet received the latest block headers from its pears. In case it is synchronizing:
|
|
// - startingBlock: block number this node started to synchronize from
|
|
// - currentBlock: block number this node is currently importing
|
|
// - highestBlock: block number of the highest block header this node has received from peers
|
|
// - pulledStates: number of state entries processed until now
|
|
// - knownStates: number of known state entries that still need to be pulled
|
|
func (e *PublicAPI) Syncing() (interface{}, error) {
|
|
e.logger.Debug("eth_syncing")
|
|
return e.backend.Syncing()
|
|
}
|
|
|
|
// Coinbase is the address that staking rewards will be send to (alias for Etherbase).
|
|
func (e *PublicAPI) Coinbase() (string, error) {
|
|
e.logger.Debug("eth_coinbase")
|
|
|
|
coinbase, err := e.backend.GetCoinbase()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ethAddr := common.BytesToAddress(coinbase.Bytes())
|
|
return ethAddr.Hex(), nil
|
|
}
|
|
|
|
// Sign signs the provided data using the private key of address via Geth's signature standard.
|
|
func (e *PublicAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
|
|
e.logger.Debug("eth_sign", "address", address.Hex(), "data", common.Bytes2Hex(data))
|
|
return e.backend.Sign(address, data)
|
|
}
|
|
|
|
// GetTransactionLogs returns the logs given a transaction hash.
|
|
func (e *PublicAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
|
|
e.logger.Debug("eth_getTransactionLogs", "hash", txHash)
|
|
|
|
hexTx := txHash.Hex()
|
|
res, err := e.backend.GetTxByEthHash(txHash)
|
|
if err != nil {
|
|
e.logger.Debug("tx not found", "hash", hexTx, "error", err.Error())
|
|
return nil, nil
|
|
}
|
|
|
|
if res.Failed {
|
|
// failed, return empty logs
|
|
return nil, nil
|
|
}
|
|
|
|
resBlockResult, err := e.backend.GetTendermintBlockResultByNumber(&res.Height)
|
|
if err != nil {
|
|
e.logger.Debug("block result not found", "number", res.Height, "error", err.Error())
|
|
return nil, nil
|
|
}
|
|
|
|
// parse tx logs from events
|
|
return backend.TxLogsFromEvents(resBlockResult.TxsResults[res.TxIndex].Events, int(res.MsgIndex))
|
|
}
|
|
|
|
// SignTypedData signs EIP-712 conformant typed data
|
|
func (e *PublicAPI) SignTypedData(address common.Address, typedData apitypes.TypedData) (hexutil.Bytes, error) {
|
|
e.logger.Debug("eth_signTypedData", "address", address.Hex(), "data", typedData)
|
|
return e.backend.SignTypedData(address, typedData)
|
|
}
|
|
|
|
// FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields)
|
|
// on a given unsigned transaction, and returns it to the caller for further
|
|
// processing (signing + broadcast).
|
|
func (e *PublicAPI) FillTransaction(args evmtypes.TransactionArgs) (*rpctypes.SignTransactionResult, error) {
|
|
// Set some sanity defaults and terminate on failure
|
|
args, err := e.backend.SetTxDefaults(args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Assemble the transaction and obtain rlp
|
|
tx := args.ToTransaction().AsTransaction()
|
|
|
|
data, err := tx.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &rpctypes.SignTransactionResult{
|
|
Raw: data,
|
|
Tx: tx,
|
|
}, nil
|
|
}
|
|
|
|
// Resend accepts an existing transaction and a new gas price and limit. It will remove
|
|
// the given transaction from the pool and reinsert it with the new gas price and limit.
|
|
func (e *PublicAPI) Resend(_ context.Context, args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) {
|
|
e.logger.Debug("eth_resend", "args", args.String())
|
|
return e.backend.Resend(args, gasPrice, gasLimit)
|
|
}
|
|
|
|
// GetPendingTransactions 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 *PublicAPI) GetPendingTransactions() ([]*rpctypes.RPCTransaction, error) {
|
|
e.logger.Debug("eth_getPendingTransactions")
|
|
|
|
txs, err := e.backend.PendingTransactions()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]*rpctypes.RPCTransaction, 0, len(txs))
|
|
for _, tx := range txs {
|
|
for _, msg := range (*tx).GetMsgs() {
|
|
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
if !ok {
|
|
// not valid ethereum tx
|
|
break
|
|
}
|
|
|
|
rpctx, err := rpctypes.NewTransactionFromMsg(
|
|
ethMsg,
|
|
common.Hash{},
|
|
uint64(0),
|
|
uint64(0),
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result = append(result, rpctx)
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|