Skip to content

Commit

Permalink
internal/ethapi: implement eth_getBlockReceipts (#27702)
Browse files Browse the repository at this point in the history
commit ethereum/go-ethereum@f1801a9.

The response is the same as eth_getTransactionReceipt but allow user to get all
receipts in a block instead of having to query each transaction as
eth_getTransactionReceipt.
  • Loading branch information
jsvisa authored and minh-bq committed Dec 9, 2024
1 parent 50d831d commit d383160
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 6 deletions.
10 changes: 10 additions & 0 deletions ethclient/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) {
return uint64(result), err
}

// BlockReceipts returns the receipts of a given block number or hash
func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.Receipt, error) {
var r []*types.Receipt
err := ec.c.CallContext(ctx, &r, "eth_getBlockReceipts", blockNrOrHash)
if err == nil && r == nil {
return nil, ethereum.NotFound
}
return r, err
}

type rpcBlock struct {
Hash common.Hash `json:"hash"`
Transactions []rpcTransaction `json:"transactions"`
Expand Down
54 changes: 48 additions & 6 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,34 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
return res[:], state.Error()
}

// GetBlockReceipts returns the block receipts for the given block hash or number or tag.
func (s *PublicBlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) {
block, err := s.b.BlockByNumberOrHash(ctx, blockNrOrHash)
if block == nil || err != nil {
// When the block doesn't exist, the RPC method should return JSON null
// as per specification.
return nil, nil
}
receipts, err := s.b.GetReceipts(ctx, block.Hash())
if err != nil {
return nil, err
}
txs := block.Transactions()
if len(txs) != len(receipts) {
return nil, fmt.Errorf("receipts length mismatch: %d vs %d", len(txs), len(receipts))
}

// Derive the sender.
signer := types.MakeSigner(s.b.ChainConfig(), block.Number())

result := make([]map[string]interface{}, len(receipts))
for i, receipt := range receipts {
result[i] = marshalReceipt(ctx, s.b, receipt, block.Hash(), block.NumberU64(), signer, txs[i], i)
}

return result, nil
}

// OverrideAccount indicates the overriding fields of account during the execution
// of a message call.
// Note, state and stateDiff can't be specified at the same time. If state is
Expand Down Expand Up @@ -1729,13 +1757,27 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
// Derive the sender.
bigblock := new(big.Int).SetUint64(blockNumber)
signer := types.MakeSigner(s.b.ChainConfig(), bigblock)
return marshalReceipt(ctx, s.b, receipt, blockHash, blockNumber, signer, tx, int(index)), nil
}

// marshalReceipt marshals a transaction receipt into a JSON object.
func marshalReceipt(
ctx context.Context,
backend Backend,
receipt *types.Receipt,
blockHash common.Hash,
blockNumber uint64,
signer types.Signer,
tx *types.Transaction,
txIndex int,
) map[string]interface{} {
from, _ := types.Sender(signer, tx)

fields := map[string]interface{}{
"blockHash": blockHash,
"blockNumber": hexutil.Uint64(blockNumber),
"transactionHash": hash,
"transactionIndex": hexutil.Uint64(index),
"transactionHash": tx.Hash(),
"transactionIndex": hexutil.Uint64(txIndex),
"from": from,
"to": tx.To(),
"gasUsed": hexutil.Uint64(receipt.GasUsed),
Expand All @@ -1751,12 +1793,12 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
}

// Assign the effective gas price paid
if !s.b.ChainConfig().IsLondon(bigblock) {
if !backend.ChainConfig().IsLondon(new(big.Int).SetUint64(blockNumber)) {
fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64())
} else {
header, err := s.b.HeaderByHash(ctx, blockHash)
header, err := backend.HeaderByHash(ctx, blockHash)
if err != nil {
return nil, err
return nil
}
gasPrice := new(big.Int).Add(header.BaseFee, tx.EffectiveGasTipValue(header.BaseFee))
fields["effectiveGasPrice"] = hexutil.Uint64(gasPrice.Uint64())
Expand All @@ -1778,7 +1820,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
if receipt.ContractAddress != (common.Address{}) {
fields["contractAddress"] = receipt.ContractAddress
}
return fields, nil
return fields
}

// sign is a helper function that signs a transaction with the private key of the given address.
Expand Down
5 changes: 5 additions & 0 deletions internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,11 @@ web3._extend({
params: 4,
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null, null],
}),
new web3._extend.Method({
name: 'getBlockReceipts',
call: 'eth_getBlockReceipts',
params: 1,
}),
],
properties: [
new web3._extend.Property({
Expand Down

0 comments on commit d383160

Please sign in to comment.