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:
HaoyangLiu 2021-03-19 13:23:30 +08:00 committed by GitHub
parent f16d8e0dd3
commit 0e2c471a94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 269 additions and 24 deletions

@ -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,