diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index a17696356c..cab25f88c8 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -70,6 +70,16 @@ func (ec *Client) ChainID(ctx context.Context) (*big.Int, error) { return (*big.Int)(&result), 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 +} + // BlockByHash returns the given full block. // // Note that loading full blocks requires two requests. Use HeaderByHash diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 73b22852a8..5e4913f7f6 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -531,6 +531,67 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI { return &PublicBlockChainAPI{b} } +// 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 +} + // ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config. func (api *PublicBlockChainAPI) ChainId() (*hexutil.Big, error) { // if current block is at or past the EIP-155 replay-protection fork block, return chainID from config diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index f1fe15d48d..bd3e54067c 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -5393,6 +5393,13 @@ var methods = function () { inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter] }); + var getTransactionReceiptsByBlockNumber = new Method({ + name: 'getTransactionReceiptsByBlockNumber', + call: 'eth_getTransactionReceiptsByBlockNumber', + params: 1, + outputFormatter: formatters.outputTransactionReceiptFormatter + }); + var estimateGas = new Method({ name: 'estimateGas', call: 'eth_estimateGas', diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index a24de36b22..7776c20b9d 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -494,6 +494,11 @@ const EthJs = ` web3._extend({ property: 'eth', methods: [ + new web3._extend.Method({ + name: 'getTransactionReceiptsByBlockNumber', + call: 'eth_getTransactionReceiptsByBlockNumber', + params: 1, + }), new web3._extend.Method({ name: 'chainId', call: 'eth_chainId',