R4R: add batch query methods (#115)
* add batch query method * GetTransactionDataAndReceipt * add new rpc to goclient * fix web3 console * rename tx_data to txData
This commit is contained in:
parent
f16d8e0dd3
commit
0e2c471a94
@ -46,6 +46,12 @@ const (
|
||||
ReceiptStatusSuccessful = uint64(1)
|
||||
)
|
||||
|
||||
// Receipt represents the results of a transaction.
|
||||
type OriginalDataAndReceipt struct {
|
||||
Receipt Receipt `json:"receipt"`
|
||||
TxData Transaction `json:"txData"`
|
||||
}
|
||||
|
||||
// Receipt represents the results of a transaction.
|
||||
type Receipt struct {
|
||||
// Consensus fields: These fields are defined by the Yellow Paper
|
||||
|
@ -265,6 +265,44 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
|
||||
return json.tx, err
|
||||
}
|
||||
|
||||
// TransactionInBlock returns a single transaction at index in the given block.
|
||||
func (ec *Client) TransactionsInBlock(ctx context.Context, number *big.Int) ([]*types.Transaction, error) {
|
||||
var rpcTxs []*rpcTransaction
|
||||
err := ec.c.CallContext(ctx, &rpcTxs, "eth_getTransactionsByBlockNumber", toBlockNumArg(number))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println(len(rpcTxs))
|
||||
txs := make([]*types.Transaction, 0, len(rpcTxs))
|
||||
for _, tx := range rpcTxs {
|
||||
txs = append(txs, tx.tx)
|
||||
}
|
||||
return txs, err
|
||||
}
|
||||
|
||||
// TransactionInBlock returns a single transaction at index in the given block.
|
||||
func (ec *Client) TransactionRecipientsInBlock(ctx context.Context, number *big.Int) ([]*types.Receipt, error) {
|
||||
var rs []*types.Receipt
|
||||
err := ec.c.CallContext(ctx, &rs, "eth_getTransactionReceiptsByBlockNumber", toBlockNumArg(number))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs, err
|
||||
}
|
||||
|
||||
// TransactionDataAndReceipt returns the original data and receipt of a transaction by transaction hash.
|
||||
// Note that the receipt is not available for pending transactions.
|
||||
func (ec *Client) TransactionDataAndReceipt(ctx context.Context, txHash common.Hash) (*types.OriginalDataAndReceipt, error) {
|
||||
var r *types.OriginalDataAndReceipt
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getTransactionDataAndReceipt", txHash)
|
||||
if err == nil {
|
||||
if r == nil {
|
||||
return nil, ethereum.NotFound
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// TransactionReceipt returns the receipt of a transaction by transaction hash.
|
||||
// Note that the receipt is not available for pending transactions.
|
||||
func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||
|
@ -1169,6 +1169,17 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
||||
return newRPCTransaction(tx, common.Hash{}, 0, 0)
|
||||
}
|
||||
|
||||
// newRPCTransactionsFromBlockIndex returns transactions that will serialize to the RPC representation.
|
||||
func newRPCTransactionsFromBlockIndex(b *types.Block) []*RPCTransaction {
|
||||
txs := b.Transactions()
|
||||
result := make([]*RPCTransaction, 0, len(txs))
|
||||
|
||||
for idx, tx := range txs {
|
||||
result = append(result, newRPCTransaction(tx, b.Hash(), b.NumberU64(), uint64(idx)))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
||||
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction {
|
||||
txs := b.Transactions()
|
||||
@ -1227,6 +1238,14 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransactionsByBlockNumber returns all the transactions for the given block number.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionsByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) []*RPCTransaction {
|
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||||
return newRPCTransactionsFromBlockIndex(block)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
|
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||||
@ -1314,6 +1333,141 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
|
||||
return rlp.EncodeToBytes(tx)
|
||||
}
|
||||
|
||||
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionReceiptsByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) ([]map[string]interface{}, error) {
|
||||
blockNumber := uint64(blockNr.Int64())
|
||||
blockHash := rawdb.ReadCanonicalHash(s.b.ChainDb(), blockNumber)
|
||||
|
||||
receipts, err := s.b.GetReceipts(ctx, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, err := s.b.BlockByHash(ctx, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txs := block.Transactions()
|
||||
if len(txs) != len(receipts) {
|
||||
return nil, fmt.Errorf("txs length doesn't equal to receipts' length")
|
||||
}
|
||||
|
||||
txReceipts := make([]map[string]interface{}, 0, len(txs))
|
||||
for idx, receipt := range receipts {
|
||||
tx := txs[idx]
|
||||
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": tx.Hash(),
|
||||
"transactionIndex": hexutil.Uint64(idx),
|
||||
"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
|
||||
}
|
||||
|
||||
txReceipts = append(txReceipts, fields)
|
||||
}
|
||||
|
||||
return txReceipts, nil
|
||||
}
|
||||
|
||||
// GetTransactionDataAndReceipt returns the original transaction data and transaction receipt for the given transaction hash.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionDataAndReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
||||
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
|
||||
if tx == nil {
|
||||
return nil, nil
|
||||
}
|
||||
receipts, err := s.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)
|
||||
|
||||
rpcTransaction := newRPCTransaction(tx, blockHash, blockNumber, index)
|
||||
|
||||
txData := map[string]interface{}{
|
||||
"blockHash": rpcTransaction.BlockHash.String(),
|
||||
"blockNumber": rpcTransaction.BlockNumber.String(),
|
||||
"from": rpcTransaction.From.String(),
|
||||
"gas": rpcTransaction.Gas.String(),
|
||||
"gasPrice": rpcTransaction.GasPrice.String(),
|
||||
"hash": rpcTransaction.Hash.String(),
|
||||
"input": rpcTransaction.Input.String(),
|
||||
"nonce": rpcTransaction.Nonce.String(),
|
||||
"to": rpcTransaction.To.String(),
|
||||
"transactionIndex": rpcTransaction.TransactionIndex.String(),
|
||||
"value": rpcTransaction.Value.String(),
|
||||
"v": rpcTransaction.V.String(),
|
||||
"r": rpcTransaction.R.String(),
|
||||
"s": rpcTransaction.S.String(),
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
result := map[string]interface{}{
|
||||
"txData": txData,
|
||||
"receipt": fields,
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
||||
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
|
||||
|
File diff suppressed because one or more lines are too long
@ -3811,6 +3811,39 @@ var outputTransactionReceiptFormatter = function (receipt){
|
||||
return receipt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the output of a transaction original data and receipt to its proper values
|
||||
*
|
||||
* @method outputTransactionDataAndReceiptFormatter
|
||||
* @param {Object} dataAndReceipt
|
||||
* @returns {Object}
|
||||
*/
|
||||
var outputTransactionDataAndReceiptFormatter = function (dataAndReceipt){
|
||||
if(dataAndReceipt.receipt.blockNumber !== null)
|
||||
dataAndReceipt.receipt.blockNumber = utils.toDecimal(dataAndReceipt.receipt.blockNumber);
|
||||
if(dataAndReceipt.receipt.transactionIndex !== null)
|
||||
dataAndReceipt.receipt.transactionIndex = utils.toDecimal(dataAndReceipt.receipt.transactionIndex);
|
||||
dataAndReceipt.receipt.cumulativeGasUsed = utils.toDecimal(dataAndReceipt.receipt.cumulativeGasUsed);
|
||||
dataAndReceipt.receipt.gasUsed = utils.toDecimal(dataAndReceipt.receipt.gasUsed);
|
||||
|
||||
if(utils.isArray(dataAndReceipt.receipt.logs)) {
|
||||
dataAndReceipt.receipt.logs = dataAndReceipt.receipt.logs.map(function(log){
|
||||
return outputLogFormatter(log);
|
||||
});
|
||||
}
|
||||
|
||||
if(dataAndReceipt.txData.blockNumber !== null)
|
||||
dataAndReceipt.txData.blockNumber = utils.toDecimal(dataAndReceipt.txData.blockNumber);
|
||||
if(dataAndReceipt.txData.transactionIndex !== null)
|
||||
dataAndReceipt.txData.transactionIndex = utils.toDecimal(dataAndReceipt.txData.transactionIndex);
|
||||
dataAndReceipt.txData.nonce = utils.toDecimal(dataAndReceipt.txData.nonce);
|
||||
dataAndReceipt.txData.gas = utils.toDecimal(dataAndReceipt.txData.gas);
|
||||
dataAndReceipt.txData.gasPrice = utils.toBigNumber(dataAndReceipt.txData.gasPrice);
|
||||
dataAndReceipt.txData.value = utils.toBigNumber(dataAndReceipt.txData.value);
|
||||
|
||||
return dataAndReceipt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the output of a block to its proper values
|
||||
*
|
||||
@ -3957,6 +3990,7 @@ module.exports = {
|
||||
outputBigNumberFormatter: outputBigNumberFormatter,
|
||||
outputTransactionFormatter: outputTransactionFormatter,
|
||||
outputTransactionReceiptFormatter: outputTransactionReceiptFormatter,
|
||||
outputTransactionDataAndReceiptFormatter: outputTransactionDataAndReceiptFormatter,
|
||||
outputBlockFormatter: outputBlockFormatter,
|
||||
outputLogFormatter: outputLogFormatter,
|
||||
outputPostFormatter: outputPostFormatter,
|
||||
@ -5343,6 +5377,27 @@ var methods = function () {
|
||||
outputFormatter: formatters.outputTransactionFormatter
|
||||
});
|
||||
|
||||
var getTransactionDataAndReceipt = new Method({
|
||||
name: 'getTransactionDataAndReceipt',
|
||||
call: 'eth_getTransactionDataAndReceipt',
|
||||
params: 1,
|
||||
outputFormatter: formatters.outputTransactionDataAndReceiptFormatter
|
||||
});
|
||||
|
||||
var getTransactionsByBlockNumber = new Method({
|
||||
name: 'getTransactionsByBlockNumber',
|
||||
call: 'eth_getTransactionsByBlockNumber',
|
||||
params: 1,
|
||||
outputFormatter: formatters.outputTransactionFormatter
|
||||
});
|
||||
|
||||
var getTransactionReceiptsByBlockNumber = new Method({
|
||||
name: 'getTransactionReceiptsByBlockNumber',
|
||||
call: 'eth_getTransactionReceiptsByBlockNumber',
|
||||
params: 1,
|
||||
outputFormatter: formatters.outputTransactionReceiptFormatter
|
||||
});
|
||||
|
||||
var getTransactionReceipt = new Method({
|
||||
name: 'getTransactionReceipt',
|
||||
call: 'eth_getTransactionReceipt',
|
||||
@ -5442,6 +5497,9 @@ var methods = function () {
|
||||
getBlockUncleCount,
|
||||
getTransaction,
|
||||
getTransactionFromBlock,
|
||||
getTransactionsByBlockNumber,
|
||||
getTransactionReceiptsByBlockNumber,
|
||||
getTransactionDataAndReceipt,
|
||||
getTransactionReceipt,
|
||||
getTransactionCount,
|
||||
call,
|
||||
|
Loading…
Reference in New Issue
Block a user