From 81074f58d87c197cf6952f442a3387f03a1bd414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Wed, 5 Jun 2024 15:19:57 +0200 Subject: [PATCH] feat: implement eth_getBlockReceipts (#796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * internal/ethapi: implement eth_getBlockReceipts (#27702) * chore: auto version bump [bot] * chore: auto version bump [bot] --------- Co-authored-by: Delweng Co-authored-by: Thegaram Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Co-authored-by: Ömer Faruk Irmak Co-authored-by: omerfirmak --- ethclient/ethclient.go | 17 ++++++++++++++ internal/ethapi/api.go | 47 +++++++++++++++++++++++++++++++++---- internal/web3ext/web3ext.go | 16 +++++++++++++ params/version.go | 2 +- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 1d110428ef..4428a866fa 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -101,6 +101,23 @@ func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) { return uint64(result), err } +// PeerCount returns the number of p2p peers as reported by the net_peerCount method. +func (ec *Client) PeerCount(ctx context.Context) (uint64, error) { + var result hexutil.Uint64 + err := ec.c.CallContext(ctx, &result, "net_peerCount") + 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"` diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b4cf9539ce..1ff887004d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -859,6 +859,40 @@ 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. + + result := make([]map[string]interface{}, len(receipts)) + for i, receipt := range receipts { + blockNumber := block.NumberU64() + bigblock := new(big.Int).SetUint64(blockNumber) + signer := types.MakeSigner(s.b.ChainConfig(), bigblock) + res, err := marshalReceipt(ctx, s.b, receipt, bigblock, block.Hash(), blockNumber, signer, txs[i], i) + if err != nil { + return nil, fmt.Errorf("failed to marshal receipt %d: %w", i, err) + } + result[i] = res + } + + 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 @@ -1663,13 +1697,18 @@ 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, bigblock, blockHash, blockNumber, signer, tx, int(index)) +} + +// marshalReceipt marshals a transaction receipt into a JSON object. +func marshalReceipt(ctx context.Context, b Backend, receipt *types.Receipt, bigblock *big.Int, blockHash common.Hash, blockNumber uint64, signer types.Signer, tx *types.Transaction, txIndex int) (map[string]interface{}, error) { 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), @@ -1681,10 +1720,10 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha "l1Fee": (*hexutil.Big)(receipt.L1Fee), } // Assign the effective gas price paid - if !s.b.ChainConfig().IsCurie(bigblock) { + if !b.ChainConfig().IsCurie(bigblock) { fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64()) } else { - header, err := s.b.HeaderByHash(ctx, blockHash) + header, err := b.HeaderByHash(ctx, blockHash) if err != nil { return nil, err } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 65778007a2..023c136871 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -577,6 +577,22 @@ web3._extend({ params: 3, inputFormatter: [null, web3._extend.formatters.inputBlockNumberFormatter, null] }), + new web3._extend.Method({ + name: 'getLogs', + call: 'eth_getLogs', + params: 1, + }), + new web3._extend.Method({ + name: 'call', + call: 'eth_call', + 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({ diff --git a/params/version.go b/params/version.go index 58788aa3b4..fd71040024 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 3 // Minor version component of the current release - VersionPatch = 36 // Patch version component of the current release + VersionPatch = 37 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string )