eth JSON-RPC #22
476
pkg/eth/api.go
476
pkg/eth/api.go
@ -28,9 +28,12 @@ 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"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@ -66,12 +69,322 @@ func NewPublicEthAPI(b *Backend, client *rpc.Client) *PublicEthAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Headers and blocks
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// GetHeaderByNumber returns the requested canonical block header.
|
||||||
|
// * When blockNr is -1 the chain head is returned.
|
||||||
|
// * We cannot support pending block calls since we do not have an active miner
|
||||||
|
func (pea *PublicEthAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) {
|
||||||
|
header, err := pea.B.HeaderByNumber(ctx, number)
|
||||||
|
if header != nil && err == nil {
|
||||||
|
return pea.rpcMarshalHeader(header)
|
||||||
|
}
|
||||||
|
if pea.ethClient != nil {
|
||||||
|
if header, err := pea.ethClient.HeaderByNumber(ctx, big.NewInt(number.Int64())); header != nil && err == nil {
|
||||||
|
return pea.rpcMarshalHeader(header)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeaderByHash returns the requested header by hash.
|
||||||
|
func (pea *PublicEthAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} {
|
||||||
|
header, err := pea.B.HeaderByHash(ctx, hash)
|
||||||
|
if header != nil && err == nil {
|
||||||
|
if res, err := pea.rpcMarshalHeader(header); err != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pea.ethClient != nil {
|
||||||
|
if header, err := pea.ethClient.HeaderByHash(ctx, hash); header != nil && err == nil {
|
||||||
|
if res, err := pea.rpcMarshalHeader(header); err != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field
|
||||||
|
func (pea *PublicEthAPI) rpcMarshalHeader(header *types.Header) (map[string]interface{}, error) {
|
||||||
|
fields := RPCMarshalHeader(header)
|
||||||
|
td, err := pea.B.GetTd(header.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fields["totalDifficulty"] = (*hexutil.Big)(td)
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BlockNumber returns the block number of the chain head.
|
// BlockNumber returns the block number of the chain head.
|
||||||
func (pea *PublicEthAPI) BlockNumber() hexutil.Uint64 {
|
func (pea *PublicEthAPI) BlockNumber() hexutil.Uint64 {
|
||||||
number, _ := pea.B.Retriever.RetrieveLastBlockNumber()
|
number, _ := pea.B.Retriever.RetrieveLastBlockNumber()
|
||||||
return hexutil.Uint64(number)
|
return hexutil.Uint64(number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlockByNumber returns the requested canonical block.
|
||||||
|
// * When blockNr is -1 the chain head is returned.
|
||||||
|
// * We cannot support pending block calls since we do not have an active miner
|
||||||
|
// * When fullTx is true all transactions in the block are returned, otherwise
|
||||||
|
// only the transaction hash is returned.
|
||||||
|
func (pea *PublicEthAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||||
|
block, err := pea.B.BlockByNumber(ctx, number)
|
||||||
|
if block != nil && err == nil {
|
||||||
|
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||||
|
}
|
||||||
|
if pea.ethClient != nil {
|
||||||
|
if block, err := pea.ethClient.BlockByNumber(ctx, big.NewInt(number.Int64())); block != nil && err == nil {
|
||||||
|
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||||
|
// detail, otherwise only the transaction hash is returned.
|
||||||
|
func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||||
|
block, err := pea.B.BlockByHash(ctx, hash)
|
||||||
|
if block != nil && err == nil {
|
||||||
|
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||||
|
}
|
||||||
|
if pea.ethClient != nil {
|
||||||
|
if block, err := pea.ethClient.BlockByHash(ctx, hash); block != nil && err == nil {
|
||||||
|
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Uncles
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
||||||
|
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||||
|
func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) {
|
||||||
|
block, err := pea.B.BlockByNumber(ctx, blockNr)
|
||||||
|
if block != nil {
|
||||||
|
uncles := block.Uncles()
|
||||||
|
if index >= hexutil.Uint(len(uncles)) {
|
||||||
|
logrus.Debugf("uncle with index %s request at block number %d was not found", index.String(), blockNr.Int64())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
block = types.NewBlockWithHeader(uncles[index])
|
||||||
|
return pea.rpcMarshalBlock(block, false, false)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
||||||
|
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||||
|
func (pea *PublicEthAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) {
|
||||||
|
block, err := pea.B.BlockByHash(ctx, blockHash)
|
||||||
|
if block != nil {
|
||||||
|
uncles := block.Uncles()
|
||||||
|
if index >= hexutil.Uint(len(uncles)) {
|
||||||
|
logrus.Debugf("uncle with index %s request at block hash %s was not found", index.String(), blockHash.Hex())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
block = types.NewBlockWithHeader(uncles[index])
|
||||||
|
return pea.rpcMarshalBlock(block, false, false)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
|
||||||
|
func (pea *PublicEthAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
|
||||||
|
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||||
|
n := hexutil.Uint(len(block.Uncles()))
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
|
||||||
|
func (pea *PublicEthAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
||||||
|
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||||
|
n := hexutil.Uint(len(block.Uncles()))
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Transactions
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
||||||
|
func (pea *PublicEthAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
|
||||||
|
// Resolve block number and use its state to ask for the nonce
|
||||||
|
state, _, err := pea.B.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nonce := state.GetNonce(address)
|
||||||
|
return (*hexutil.Uint64)(&nonce), state.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
||||||
|
func (pea *PublicEthAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
|
||||||
|
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||||
|
n := hexutil.Uint(len(block.Transactions()))
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
||||||
|
func (pea *PublicEthAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
||||||
|
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||||
|
n := hexutil.Uint(len(block.Transactions()))
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
||||||
|
func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
|
||||||
|
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||||
|
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
|
||||||
|
func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
|
||||||
|
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||||
|
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
|
||||||
|
func (pea *PublicEthAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes {
|
||||||
|
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||||
|
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index.
|
||||||
|
func (pea *PublicEthAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes {
|
||||||
|
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||||
|
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionByHash returns the transaction for the given hash
|
||||||
|
// eth ipld-eth-server cannot currently handle pending/tx_pool txs
|
||||||
|
func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
||||||
|
tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash)
|
||||||
|
if tx != nil && err == nil {
|
||||||
|
return NewRPCTransaction(tx, blockHash, blockNumber, index), nil
|
||||||
|
}
|
||||||
|
if pea.rpc != nil {
|
||||||
|
if tx, err := pea.remoteGetTransactionByHash(ctx, hash); tx != nil && err == nil {
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pea *PublicEthAPI) remoteGetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
||||||
|
var tx *RPCTransaction
|
||||||
|
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", hash); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
|
||||||
|
func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
|
||||||
|
// Retrieve a finalized transaction, or a pooled otherwise
|
||||||
|
tx, _, _, _, err := pea.B.GetTransaction(ctx, hash)
|
||||||
|
if tx != nil && err == nil {
|
||||||
|
return rlp.EncodeToBytes(tx)
|
||||||
|
}
|
||||||
|
if pea.rpc != nil {
|
||||||
|
if tx, err := pea.remoteGetRawTransactionByHash(ctx, hash); tx != nil && err == nil {
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pea *PublicEthAPI) remoteGetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
|
||||||
|
var tx hexutil.Bytes
|
||||||
|
if err := pea.rpc.CallContext(ctx, &tx, "eth_getRawTransactionByHash", hash); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Receipts and Logs
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
||||||
|
func (pea *PublicEthAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
||||||
|
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(pea.B.ChainDb(), hash)
|
||||||
|
if tx == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
receipts, err := pea.B.GetReceipts(ctx, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(receipts) <= int(index) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
receipt := receipts[index]
|
||||||
|
|
||||||
|
var signer types.Signer = types.FrontierSigner{}
|
||||||
|
if tx.Protected() {
|
||||||
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
|
}
|
||||||
|
from, _ := types.Sender(signer, tx)
|
||||||
|
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"blockHash": blockHash,
|
||||||
|
"blockNumber": hexutil.Uint64(blockNumber),
|
||||||
|
"transactionHash": hash,
|
||||||
|
"transactionIndex": hexutil.Uint64(index),
|
||||||
|
"from": from,
|
||||||
|
"to": tx.To(),
|
||||||
|
"gasUsed": hexutil.Uint64(receipt.GasUsed),
|
||||||
|
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
|
||||||
|
"contractAddress": nil,
|
||||||
|
"logs": receipt.Logs,
|
||||||
|
"logsBloom": receipt.Bloom,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign receipt status or post state.
|
||||||
|
if len(receipt.PostState) > 0 {
|
||||||
|
fields["root"] = hexutil.Bytes(receipt.PostState)
|
||||||
|
} else {
|
||||||
|
fields["status"] = hexutil.Uint(receipt.Status)
|
||||||
|
}
|
||||||
|
if receipt.Logs == nil {
|
||||||
|
fields["logs"] = [][]*types.Log{}
|
||||||
|
}
|
||||||
|
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
|
||||||
|
if receipt.ContractAddress != (common.Address{}) {
|
||||||
|
fields["contractAddress"] = receipt.ContractAddress
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetLogs returns logs matching the given argument that are stored within the state.
|
// GetLogs returns logs matching the given argument that are stored within the state.
|
||||||
//
|
//
|
||||||
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
||||||
@ -175,76 +488,109 @@ func (pea *PublicEthAPI) getLogs(ctx context.Context, crit ethereum.FilterQuery)
|
|||||||
return logs, err // need to return err variable so that we return the err = tx.Commit() assignment in the defer
|
return logs, err // need to return err variable so that we return the err = tx.Commit() assignment in the defer
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeaderByNumber returns the requested canonical block header.
|
/*
|
||||||
// * When blockNr is -1 the chain head is returned.
|
|
||||||
// * We cannot support pending block calls since we do not have an active miner
|
|
||||||
func (pea *PublicEthAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) {
|
|
||||||
header, err := pea.B.HeaderByNumber(ctx, number)
|
|
||||||
if header != nil && err == nil {
|
|
||||||
return pea.rpcMarshalHeader(header)
|
|
||||||
}
|
|
||||||
if pea.ethClient != nil {
|
|
||||||
if header, err := pea.ethClient.HeaderByNumber(ctx, big.NewInt(number.Int64())); header != nil && err == nil {
|
|
||||||
return pea.rpcMarshalHeader(header)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBlockByNumber returns the requested canonical block.
|
State and Storage
|
||||||
// * When blockNr is -1 the chain head is returned.
|
|
||||||
// * We cannot support pending block calls since we do not have an active miner
|
|
||||||
// * When fullTx is true all transactions in the block are returned, otherwise
|
|
||||||
// only the transaction hash is returned.
|
|
||||||
func (pea *PublicEthAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
|
||||||
block, err := pea.B.BlockByNumber(ctx, number)
|
|
||||||
if block != nil && err == nil {
|
|
||||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
|
||||||
}
|
|
||||||
if pea.ethClient != nil {
|
|
||||||
if block, err := pea.ethClient.BlockByNumber(ctx, big.NewInt(number.Int64())); block != nil && err == nil {
|
|
||||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
*/
|
||||||
// detail, otherwise only the transaction hash is returned.
|
|
||||||
func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
|
||||||
block, err := pea.B.BlockByHash(ctx, hash)
|
|
||||||
if block != nil && err == nil {
|
|
||||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
|
||||||
}
|
|
||||||
if pea.ethClient != nil {
|
|
||||||
if block, err := pea.ethClient.BlockByHash(ctx, hash); block != nil && err == nil {
|
|
||||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTransactionByHash returns the transaction for the given hash
|
// GetBalance returns the amount of wei for the given address in the state of the
|
||||||
// eth ipld-eth-server cannot currently handle pending/tx_pool txs
|
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||||
func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
// block numbers are also allowed.
|
||||||
tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash)
|
func (pea *PublicEthAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
|
||||||
if tx != nil && err == nil {
|
state, _, err := pea.B.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
return NewRPCTransaction(tx, blockHash, blockNumber, index), nil
|
if state == nil || err != nil {
|
||||||
}
|
|
||||||
if pea.rpc != nil {
|
|
||||||
if tx, err := pea.remoteGetTransactionByHash(ctx, hash); tx != nil && err == nil {
|
|
||||||
return tx, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pea *PublicEthAPI) remoteGetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
|
||||||
var tx *RPCTransaction
|
|
||||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", hash); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return tx, nil
|
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStorageAt returns the storage from the state at the given address, key and
|
||||||
|
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
||||||
|
// numbers are also allowed.
|
||||||
|
func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||||
|
state, _, err := pea.B.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res := state.GetState(address, common.HexToHash(key))
|
||||||
|
return res[:], state.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCode returns the code stored at the given address in the state for the given block number.
|
||||||
|
func (pea *PublicEthAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||||
|
state, _, err := pea.B.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
code := state.GetCode(address)
|
||||||
|
return code, state.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result structs for GetProof
|
||||||
|
type AccountResult struct {
|
||||||
|
Address common.Address `json:"address"`
|
||||||
|
AccountProof []string `json:"accountProof"`
|
||||||
|
Balance *hexutil.Big `json:"balance"`
|
||||||
|
CodeHash common.Hash `json:"codeHash"`
|
||||||
|
Nonce hexutil.Uint64 `json:"nonce"`
|
||||||
|
StorageHash common.Hash `json:"storageHash"`
|
||||||
|
StorageProof []StorageResult `json:"storageProof"`
|
||||||
|
}
|
||||||
|
type StorageResult struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value *hexutil.Big `json:"value"`
|
||||||
|
Proof []string `json:"proof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
|
||||||
|
func (pea *PublicEthAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
|
||||||
|
state, _, err := pea.B.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
storageTrie := state.StorageTrie(address)
|
||||||
|
storageHash := types.EmptyRootHash
|
||||||
|
codeHash := state.GetCodeHash(address)
|
||||||
|
storageProof := make([]StorageResult, len(storageKeys))
|
||||||
|
|
||||||
|
// if we have a storageTrie, (which means the account exists), we can update the storagehash
|
||||||
|
if storageTrie != nil {
|
||||||
|
storageHash = storageTrie.Hash()
|
||||||
|
} else {
|
||||||
|
// no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray.
|
||||||
|
codeHash = crypto.Keccak256Hash(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the proof for the storageKeys
|
||||||
|
for i, key := range storageKeys {
|
||||||
|
if storageTrie != nil {
|
||||||
|
proof, storageError := state.GetStorageProof(address, common.HexToHash(key))
|
||||||
|
if storageError != nil {
|
||||||
|
return nil, storageError
|
||||||
|
}
|
||||||
|
storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), common.ToHexArray(proof)}
|
||||||
|
} else {
|
||||||
|
storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the accountProof
|
||||||
|
accountProof, proofErr := state.GetProof(address)
|
||||||
|
if proofErr != nil {
|
||||||
|
return nil, proofErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &AccountResult{
|
||||||
|
Address: address,
|
||||||
|
AccountProof: common.ToHexArray(accountProof),
|
||||||
|
Balance: (*hexutil.Big)(state.GetBalance(address)),
|
||||||
|
CodeHash: codeHash,
|
||||||
|
Nonce: hexutil.Uint64(state.GetNonce(address)),
|
||||||
|
StorageHash: storageHash,
|
||||||
|
StorageProof: storageProof,
|
||||||
|
}, state.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call executes the given transaction on the state for the given block number.
|
// Call executes the given transaction on the state for the given block number.
|
||||||
|
@ -21,19 +21,18 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
@ -167,18 +166,6 @@ func (b *Backend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.Bl
|
|||||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires
|
|
||||||
// a `PublicEthAPI`.
|
|
||||||
func (pea *PublicEthAPI) rpcMarshalHeader(header *types.Header) (map[string]interface{}, error) {
|
|
||||||
fields := RPCMarshalHeader(header)
|
|
||||||
td, err := pea.B.GetTd(header.Hash())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fields["totalDifficulty"] = (*hexutil.Big)(td)
|
|
||||||
return fields, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTd gets the total difficulty at the given block hash
|
// GetTd gets the total difficulty at the given block hash
|
||||||
func (b *Backend) GetTd(blockHash common.Hash) (*big.Int, error) {
|
func (b *Backend) GetTd(blockHash common.Hash) (*big.Int, error) {
|
||||||
var tdStr string
|
var tdStr string
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -127,6 +128,16 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
|
||||||
|
func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes {
|
||||||
|
txs := b.Transactions()
|
||||||
|
if index >= uint64(len(txs)) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
blob, _ := rlp.EncodeToBytes(txs[index])
|
||||||
|
return blob
|
||||||
|
}
|
||||||
|
|
||||||
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
||||||
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction {
|
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction {
|
||||||
txs := b.Transactions()
|
txs := b.Transactions()
|
||||||
|
Loading…
Reference in New Issue
Block a user