2020-08-01 07:39:04 +00:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
2021-06-23 22:33:45 +00:00
|
|
|
"bytes"
|
2020-08-01 07:39:04 +00:00
|
|
|
"context"
|
2021-06-23 22:33:45 +00:00
|
|
|
"encoding/binary"
|
2020-08-01 07:39:04 +00:00
|
|
|
"fmt"
|
2020-10-07 20:50:03 +00:00
|
|
|
"math/big"
|
|
|
|
|
2021-07-02 13:34:20 +00:00
|
|
|
"github.com/holiman/uint256"
|
2021-07-29 11:53:13 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
2022-06-04 22:06:30 +00:00
|
|
|
"github.com/ledgerwatch/log/v3"
|
2021-07-02 13:34:20 +00:00
|
|
|
|
2020-10-02 08:16:21 +00:00
|
|
|
"github.com/RoaringBitmap/roaring"
|
2021-05-20 18:25:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/common"
|
|
|
|
"github.com/ledgerwatch/erigon/common/dbutils"
|
|
|
|
"github.com/ledgerwatch/erigon/common/hexutil"
|
|
|
|
"github.com/ledgerwatch/erigon/consensus/ethash"
|
|
|
|
"github.com/ledgerwatch/erigon/core"
|
|
|
|
"github.com/ledgerwatch/erigon/core/rawdb"
|
|
|
|
"github.com/ledgerwatch/erigon/core/state"
|
|
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
|
|
"github.com/ledgerwatch/erigon/core/vm"
|
|
|
|
"github.com/ledgerwatch/erigon/eth/filters"
|
|
|
|
"github.com/ledgerwatch/erigon/ethdb"
|
|
|
|
"github.com/ledgerwatch/erigon/ethdb/bitmapdb"
|
2021-06-23 22:33:45 +00:00
|
|
|
"github.com/ledgerwatch/erigon/ethdb/cbor"
|
2021-05-20 18:25:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/params"
|
|
|
|
"github.com/ledgerwatch/erigon/rpc"
|
2022-06-14 08:07:46 +00:00
|
|
|
"github.com/ledgerwatch/erigon/turbo/rpchelper"
|
2021-05-20 18:25:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/turbo/transactions"
|
2020-08-01 07:39:04 +00:00
|
|
|
)
|
|
|
|
|
2022-06-04 22:06:30 +00:00
|
|
|
func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *params.ChainConfig, block *types.Block, senders []common.Address) (types.Receipts, error) {
|
2021-06-04 12:28:18 +00:00
|
|
|
if cached := rawdb.ReadReceipts(tx, block, senders); cached != nil {
|
2020-08-01 07:39:04 +00:00
|
|
|
return cached, nil
|
|
|
|
}
|
|
|
|
|
2021-04-06 09:52:53 +00:00
|
|
|
getHeader := func(hash common.Hash, number uint64) *types.Header {
|
2022-06-04 22:06:30 +00:00
|
|
|
h, e := api._blockReader.Header(ctx, tx, hash, number)
|
|
|
|
if e != nil {
|
|
|
|
log.Error("getHeader error", "number", number, "hash", hash, "err", e)
|
|
|
|
}
|
|
|
|
return h
|
2021-04-06 09:52:53 +00:00
|
|
|
}
|
2021-08-10 02:48:56 +00:00
|
|
|
contractHasTEVM := ethdb.GetHasTEVM(tx)
|
|
|
|
_, _, _, ibs, _, err := transactions.ComputeTxEnv(ctx, block, chainConfig, getHeader, contractHasTEVM, ethash.NewFaker(), tx, block.Hash(), 0)
|
2020-08-01 07:39:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-10-11 14:24:21 +00:00
|
|
|
usedGas := new(uint64)
|
2020-08-01 07:39:04 +00:00
|
|
|
gp := new(core.GasPool).AddGas(block.GasLimit())
|
2021-10-11 14:24:21 +00:00
|
|
|
|
|
|
|
ethashFaker := ethash.NewFaker()
|
|
|
|
noopWriter := state.NewNoopWriter()
|
|
|
|
|
|
|
|
receipts := make(types.Receipts, len(block.Transactions()))
|
|
|
|
|
2020-09-28 17:18:36 +00:00
|
|
|
for i, txn := range block.Transactions() {
|
|
|
|
ibs.Prepare(txn.Hash(), block.Hash(), i)
|
2022-07-07 11:47:00 +00:00
|
|
|
header := block.Header()
|
|
|
|
receipt, _, err := core.ApplyTransaction(chainConfig, core.GetHashFn(header, getHeader), ethashFaker, nil, gp, ibs, noopWriter, header, txn, usedGas, vm.Config{}, contractHasTEVM)
|
2020-08-01 07:39:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-07-02 13:34:20 +00:00
|
|
|
receipt.BlockHash = block.Hash()
|
2021-10-11 14:24:21 +00:00
|
|
|
receipts[i] = receipt
|
2020-08-01 07:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return receipts, nil
|
|
|
|
}
|
|
|
|
|
2020-10-24 17:03:52 +00:00
|
|
|
// GetLogs implements eth_getLogs. Returns an array of logs matching a given filter object.
|
2020-09-28 17:18:36 +00:00
|
|
|
func (api *APIImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*types.Log, error) {
|
|
|
|
var begin, end uint64
|
2022-03-25 04:17:23 +00:00
|
|
|
logs := []*types.Log{}
|
2020-09-03 07:51:19 +00:00
|
|
|
|
2021-04-03 06:26:00 +00:00
|
|
|
tx, beginErr := api.db.BeginRo(ctx)
|
2020-09-28 17:18:36 +00:00
|
|
|
if beginErr != nil {
|
2022-03-25 04:17:23 +00:00
|
|
|
return logs, beginErr
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
2020-09-28 17:18:36 +00:00
|
|
|
defer tx.Rollback()
|
2020-09-03 07:51:19 +00:00
|
|
|
|
|
|
|
if crit.BlockHash != nil {
|
2022-08-10 16:03:22 +00:00
|
|
|
header, err := api._blockReader.HeaderByHash(ctx, tx, *crit.BlockHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if header == nil {
|
2020-09-28 17:18:36 +00:00
|
|
|
return nil, fmt.Errorf("block not found: %x", *crit.BlockHash)
|
|
|
|
}
|
2022-08-10 16:03:22 +00:00
|
|
|
begin = header.Number.Uint64()
|
|
|
|
end = header.Number.Uint64()
|
2020-09-03 07:51:19 +00:00
|
|
|
} else {
|
|
|
|
// Convert the RPC block numbers into internal representations
|
2022-08-10 16:03:22 +00:00
|
|
|
latest, _, _, err := rpchelper.GetBlockNumber(rpc.BlockNumberOrHashWithNumber(rpc.LatestExecutedBlockNumber), tx, nil)
|
2020-09-03 07:51:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-03 12:36:52 +00:00
|
|
|
begin = latest
|
2021-11-18 14:05:20 +00:00
|
|
|
if crit.FromBlock != nil {
|
|
|
|
if crit.FromBlock.Sign() >= 0 {
|
|
|
|
begin = crit.FromBlock.Uint64()
|
2021-12-03 12:36:52 +00:00
|
|
|
} else if !crit.FromBlock.IsInt64() || crit.FromBlock.Int64() != int64(rpc.LatestBlockNumber) {
|
2021-11-18 14:05:20 +00:00
|
|
|
return nil, fmt.Errorf("negative value for FromBlock: %v", crit.FromBlock)
|
|
|
|
}
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
2020-09-28 17:18:36 +00:00
|
|
|
end = latest
|
2021-11-18 14:05:20 +00:00
|
|
|
if crit.ToBlock != nil {
|
|
|
|
if crit.ToBlock.Sign() >= 0 {
|
|
|
|
end = crit.ToBlock.Uint64()
|
2021-12-03 12:36:52 +00:00
|
|
|
} else if !crit.ToBlock.IsInt64() || crit.ToBlock.Int64() != int64(rpc.LatestBlockNumber) {
|
2021-11-18 14:05:20 +00:00
|
|
|
return nil, fmt.Errorf("negative value for ToBlock: %v", crit.ToBlock)
|
|
|
|
}
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
|
|
|
}
|
2021-11-18 14:05:20 +00:00
|
|
|
if end < begin {
|
|
|
|
return nil, fmt.Errorf("end (%d) < begin (%d)", end, begin)
|
|
|
|
}
|
2022-08-11 02:16:40 +00:00
|
|
|
if end > roaring.MaxUint32 {
|
|
|
|
latest, err := rpchelper.GetLatestBlockNumber(tx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if begin > latest {
|
|
|
|
return nil, fmt.Errorf("begin (%d) > latest (%d)", begin, latest)
|
|
|
|
}
|
|
|
|
end = latest
|
|
|
|
}
|
2020-10-02 08:16:21 +00:00
|
|
|
blockNumbers := roaring.New()
|
2020-09-28 17:18:36 +00:00
|
|
|
blockNumbers.AddRange(begin, end+1) // [min,max)
|
2020-10-25 08:38:55 +00:00
|
|
|
topicsBitmap, err := getTopicsBitmap(tx, crit.Topics, uint32(begin), uint32(end))
|
2020-09-03 07:51:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-08-10 16:03:22 +00:00
|
|
|
|
2020-09-28 17:18:36 +00:00
|
|
|
if topicsBitmap != nil {
|
2022-03-25 04:17:23 +00:00
|
|
|
blockNumbers.And(topicsBitmap)
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 08:16:21 +00:00
|
|
|
var addrBitmap *roaring.Bitmap
|
2020-09-28 17:18:36 +00:00
|
|
|
for _, addr := range crit.Addresses {
|
2021-07-28 02:47:38 +00:00
|
|
|
m, err := bitmapdb.Get(tx, kv.LogAddressIndex, addr[:], uint32(begin), uint32(end))
|
2020-09-28 17:18:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if addrBitmap == nil {
|
|
|
|
addrBitmap = m
|
2022-03-25 04:17:23 +00:00
|
|
|
continue
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2022-03-25 04:17:23 +00:00
|
|
|
addrBitmap = roaring.Or(addrBitmap, m)
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2020-09-03 07:51:19 +00:00
|
|
|
|
2020-09-28 17:18:36 +00:00
|
|
|
if addrBitmap != nil {
|
2022-03-25 04:17:23 +00:00
|
|
|
blockNumbers.And(addrBitmap)
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
2020-09-28 17:18:36 +00:00
|
|
|
|
2020-10-02 08:16:21 +00:00
|
|
|
if blockNumbers.GetCardinality() == 0 {
|
2022-03-25 04:17:23 +00:00
|
|
|
return logs, nil
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 22:33:45 +00:00
|
|
|
iter := blockNumbers.Iterator()
|
|
|
|
for iter.HasNext() {
|
2022-03-25 04:17:23 +00:00
|
|
|
if err = ctx.Err(); err != nil {
|
2021-07-21 02:37:29 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-07-09 13:42:57 +00:00
|
|
|
blockNumber := uint64(iter.Next())
|
2021-06-23 22:33:45 +00:00
|
|
|
var logIndex uint
|
2022-07-09 03:15:22 +00:00
|
|
|
var txIndex uint
|
2022-03-25 04:17:23 +00:00
|
|
|
var blockLogs []*types.Log
|
2022-07-09 13:42:57 +00:00
|
|
|
err := tx.ForPrefix(kv.Log, dbutils.EncodeBlockNumber(blockNumber), func(k, v []byte) error {
|
2021-06-23 22:33:45 +00:00
|
|
|
var logs types.Logs
|
|
|
|
if err := cbor.Unmarshal(&logs, bytes.NewReader(v)); err != nil {
|
|
|
|
return fmt.Errorf("receipt unmarshal failed: %w", err)
|
|
|
|
}
|
|
|
|
for _, log := range logs {
|
|
|
|
log.Index = logIndex
|
|
|
|
logIndex++
|
|
|
|
}
|
|
|
|
filtered := filterLogs(logs, crit.Addresses, crit.Topics)
|
2022-03-25 04:17:23 +00:00
|
|
|
if len(filtered) == 0 {
|
|
|
|
return nil
|
2021-06-23 22:33:45 +00:00
|
|
|
}
|
2022-07-09 03:15:22 +00:00
|
|
|
txIndex = uint(binary.BigEndian.Uint32(k[8:]))
|
2022-03-25 04:17:23 +00:00
|
|
|
for _, log := range filtered {
|
|
|
|
log.TxIndex = txIndex
|
|
|
|
}
|
|
|
|
blockLogs = append(blockLogs, filtered...)
|
|
|
|
|
2021-06-23 22:33:45 +00:00
|
|
|
return nil
|
2022-03-25 04:17:23 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return logs, err
|
|
|
|
}
|
|
|
|
if len(blockLogs) == 0 {
|
|
|
|
continue
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
2021-07-21 02:37:29 +00:00
|
|
|
|
2022-07-09 13:42:57 +00:00
|
|
|
blockHash, err := rawdb.ReadCanonicalHash(tx, blockNumber)
|
2022-03-25 04:17:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-07-09 13:42:57 +00:00
|
|
|
|
|
|
|
body, err := api._blockReader.BodyWithTransactions(ctx, tx, blockHash, blockNumber)
|
2022-07-10 02:13:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if body == nil {
|
2022-07-09 13:42:57 +00:00
|
|
|
return nil, fmt.Errorf("block not found %d", blockNumber)
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2022-03-25 04:17:23 +00:00
|
|
|
for _, log := range blockLogs {
|
2022-07-09 13:42:57 +00:00
|
|
|
log.BlockNumber = blockNumber
|
2022-03-25 04:17:23 +00:00
|
|
|
log.BlockHash = blockHash
|
2022-07-09 13:42:57 +00:00
|
|
|
log.TxHash = body.Transactions[log.TxIndex].Hash()
|
2022-03-25 04:17:23 +00:00
|
|
|
}
|
|
|
|
logs = append(logs, blockLogs...)
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
2022-03-25 04:17:23 +00:00
|
|
|
|
|
|
|
return logs, nil
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2020-09-03 07:51:19 +00:00
|
|
|
|
2020-09-28 17:18:36 +00:00
|
|
|
// The Topic list restricts matches to particular event topics. Each event has a list
|
|
|
|
// of topics. Topics matches a prefix of that list. An empty element slice matches any
|
|
|
|
// topic. Non-empty elements represent an alternative that matches any of the
|
|
|
|
// contained topics.
|
|
|
|
//
|
|
|
|
// Examples:
|
|
|
|
// {} or nil matches any topic list
|
|
|
|
// {{A}} matches topic A in first position
|
|
|
|
// {{}, {B}} matches any topic in first position AND B in second position
|
|
|
|
// {{A}, {B}} matches topic A in first position AND B in second position
|
|
|
|
// {{A, B}, {C, D}} matches topic (A OR B) in first position AND (C OR D) in second position
|
2021-07-28 02:47:38 +00:00
|
|
|
func getTopicsBitmap(c kv.Tx, topics [][]common.Hash, from, to uint32) (*roaring.Bitmap, error) {
|
2020-10-02 08:16:21 +00:00
|
|
|
var result *roaring.Bitmap
|
2020-09-28 17:18:36 +00:00
|
|
|
for _, sub := range topics {
|
2020-10-02 08:16:21 +00:00
|
|
|
var bitmapForORing *roaring.Bitmap
|
2020-09-28 17:18:36 +00:00
|
|
|
for _, topic := range sub {
|
2021-07-28 02:47:38 +00:00
|
|
|
m, err := bitmapdb.Get(c, kv.LogTopicIndex, topic[:], from, to)
|
2020-09-28 17:18:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if bitmapForORing == nil {
|
|
|
|
bitmapForORing = m
|
2022-03-25 04:17:23 +00:00
|
|
|
continue
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2022-03-25 04:17:23 +00:00
|
|
|
bitmapForORing.Or(m)
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2020-09-03 07:51:19 +00:00
|
|
|
|
2022-03-25 04:17:23 +00:00
|
|
|
if bitmapForORing == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if result == nil {
|
|
|
|
result = bitmapForORing
|
|
|
|
continue
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
2022-08-10 16:03:22 +00:00
|
|
|
|
2022-03-25 04:17:23 +00:00
|
|
|
result = roaring.And(bitmapForORing, result)
|
2020-09-28 17:18:36 +00:00
|
|
|
}
|
|
|
|
return result, nil
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
|
|
|
|
2020-10-24 17:03:52 +00:00
|
|
|
// GetTransactionReceipt implements eth_getTransactionReceipt. Returns the receipt of a transaction given the transaction's hash.
|
2022-07-09 03:15:22 +00:00
|
|
|
func (api *APIImpl) GetTransactionReceipt(ctx context.Context, txnHash common.Hash) (map[string]interface{}, error) {
|
2021-04-03 06:26:00 +00:00
|
|
|
tx, err := api.db.BeginRo(ctx)
|
2020-10-10 12:24:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
2022-02-07 21:30:46 +00:00
|
|
|
var blockNum uint64
|
|
|
|
var ok bool
|
|
|
|
|
2022-07-09 03:15:22 +00:00
|
|
|
blockNum, ok, err = api.txnLookup(ctx, tx, txnHash)
|
2022-07-07 08:40:50 +00:00
|
|
|
if !ok || blockNum == 0 {
|
2022-05-22 19:35:02 +00:00
|
|
|
// It is not an ideal solution (ideal solution requires extending TxnLookupReply proto type to include bool flag indicating absense of result),
|
|
|
|
// but 0 block number is used here to mean that the transaction is not found
|
|
|
|
return nil, nil
|
|
|
|
}
|
2022-05-19 13:03:58 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-02-07 21:30:46 +00:00
|
|
|
|
2022-01-07 13:52:38 +00:00
|
|
|
block, err := api.blockByNumberWithSenders(tx, blockNum)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2021-06-04 12:28:18 +00:00
|
|
|
}
|
|
|
|
if block == nil {
|
2022-01-07 13:52:38 +00:00
|
|
|
return nil, nil // not error, see https://github.com/ledgerwatch/erigon/issues/1645
|
2021-06-04 12:28:18 +00:00
|
|
|
}
|
2022-02-07 21:30:46 +00:00
|
|
|
|
|
|
|
cc, err := api.chainConfig(tx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-07 13:52:38 +00:00
|
|
|
var txnIndex uint64
|
|
|
|
var txn types.Transaction
|
2022-02-07 21:30:46 +00:00
|
|
|
for idx, transaction := range block.Transactions() {
|
2022-07-09 03:15:22 +00:00
|
|
|
if transaction.Hash() == txnHash {
|
2022-01-07 13:52:38 +00:00
|
|
|
txn = transaction
|
2022-02-07 21:30:46 +00:00
|
|
|
txnIndex = uint64(idx)
|
2021-06-04 12:28:18 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2022-02-07 21:30:46 +00:00
|
|
|
|
2022-01-07 13:52:38 +00:00
|
|
|
if txn == nil {
|
2022-07-07 08:40:50 +00:00
|
|
|
if cc.Bor == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2022-07-09 03:15:22 +00:00
|
|
|
borTx, blockHash, _, _, err := rawdb.ReadBorTransactionForBlockNumber(tx, blockNum)
|
2022-07-07 08:40:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if borTx == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
borReceipt := rawdb.ReadBorReceipt(tx, blockHash, blockNum)
|
2022-07-09 03:15:22 +00:00
|
|
|
if borReceipt == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return marshalReceipt(borReceipt, borTx, cc, block, txnHash, false), nil
|
2021-11-21 09:22:29 +00:00
|
|
|
}
|
2021-06-04 12:28:18 +00:00
|
|
|
|
2022-06-04 22:06:30 +00:00
|
|
|
receipts, err := api.getReceipts(ctx, tx, cc, block, block.Body().SendersFromTxs())
|
2020-08-01 07:39:04 +00:00
|
|
|
if err != nil {
|
2021-10-04 15:16:52 +00:00
|
|
|
return nil, fmt.Errorf("getReceipts error: %w", err)
|
2020-08-01 07:39:04 +00:00
|
|
|
}
|
2022-01-07 13:52:38 +00:00
|
|
|
if len(receipts) <= int(txnIndex) {
|
|
|
|
return nil, fmt.Errorf("block has less receipts than expected: %d <= %d, block: %d", len(receipts), int(txnIndex), blockNum)
|
2020-08-01 07:39:04 +00:00
|
|
|
}
|
2022-07-09 03:15:22 +00:00
|
|
|
return marshalReceipt(receipts[txnIndex], block.Transactions()[txnIndex], cc, block, txnHash, true), nil
|
2021-04-18 05:05:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockReceipts - receipts for individual block
|
2022-02-07 21:30:46 +00:00
|
|
|
// func (api *APIImpl) GetBlockReceipts(ctx context.Context, number rpc.BlockNumber) ([]map[string]interface{}, error) {
|
2021-04-18 05:05:54 +00:00
|
|
|
func (api *APIImpl) GetBlockReceipts(ctx context.Context, number rpc.BlockNumber) ([]map[string]interface{}, error) {
|
|
|
|
tx, err := api.db.BeginRo(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
2020-08-01 07:39:04 +00:00
|
|
|
|
2022-06-14 13:29:49 +00:00
|
|
|
blockNum, _, _, err := rpchelper.GetBlockNumber(rpc.BlockNumberOrHashWithNumber(number), tx, api.filters)
|
2021-04-18 05:05:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-09-29 06:51:51 +00:00
|
|
|
block, err := api.blockByNumberWithSenders(tx, blockNum)
|
2021-04-18 05:05:54 +00:00
|
|
|
if err != nil {
|
2021-06-04 12:28:18 +00:00
|
|
|
return nil, err
|
2021-04-18 05:05:54 +00:00
|
|
|
}
|
|
|
|
if block == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
chainConfig, err := api.chainConfig(tx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-06-04 22:06:30 +00:00
|
|
|
receipts, err := api.getReceipts(ctx, tx, chainConfig, block, block.Body().SendersFromTxs())
|
2021-04-18 05:05:54 +00:00
|
|
|
if err != nil {
|
2021-10-04 15:16:52 +00:00
|
|
|
return nil, fmt.Errorf("getReceipts error: %w", err)
|
2021-04-18 05:05:54 +00:00
|
|
|
}
|
|
|
|
result := make([]map[string]interface{}, 0, len(receipts))
|
|
|
|
for _, receipt := range receipts {
|
|
|
|
txn := block.Transactions()[receipt.TransactionIndex]
|
2022-07-09 03:15:22 +00:00
|
|
|
result = append(result, marshalReceipt(receipt, txn, chainConfig, block, txn.Hash(), true))
|
2021-04-18 05:05:54 +00:00
|
|
|
}
|
|
|
|
|
2022-07-07 08:40:50 +00:00
|
|
|
if chainConfig.Bor != nil {
|
2022-07-09 03:15:22 +00:00
|
|
|
borTx, _, _, _ := rawdb.ReadBorTransactionForBlock(tx, block)
|
2022-07-07 08:40:50 +00:00
|
|
|
if borTx != nil {
|
|
|
|
borReceipt := rawdb.ReadBorReceipt(tx, block.Hash(), blockNum)
|
|
|
|
if borReceipt != nil {
|
2022-07-09 03:15:22 +00:00
|
|
|
result = append(result, marshalReceipt(borReceipt, borTx, chainConfig, block, borReceipt.TxHash, false))
|
2022-07-07 08:40:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-18 05:05:54 +00:00
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2022-07-09 03:15:22 +00:00
|
|
|
func marshalReceipt(receipt *types.Receipt, txn types.Transaction, chainConfig *params.ChainConfig, block *types.Block, txnHash common.Hash, signed bool) map[string]interface{} {
|
2021-04-23 19:48:00 +00:00
|
|
|
var chainId *big.Int
|
2021-04-22 17:11:37 +00:00
|
|
|
switch t := txn.(type) {
|
|
|
|
case *types.LegacyTx:
|
|
|
|
if t.Protected() {
|
2021-04-23 19:48:00 +00:00
|
|
|
chainId = types.DeriveChainId(&t.V).ToBig()
|
2021-04-22 17:11:37 +00:00
|
|
|
}
|
|
|
|
case *types.AccessListTx:
|
2021-04-23 19:48:00 +00:00
|
|
|
chainId = t.ChainID.ToBig()
|
2021-04-22 17:11:37 +00:00
|
|
|
case *types.DynamicFeeTransaction:
|
2021-04-23 19:48:00 +00:00
|
|
|
chainId = t.ChainID.ToBig()
|
2020-08-01 07:39:04 +00:00
|
|
|
}
|
2022-07-09 03:15:22 +00:00
|
|
|
|
|
|
|
var from common.Address
|
|
|
|
if signed {
|
|
|
|
signer := types.LatestSignerForChainID(chainId)
|
|
|
|
from, _ = txn.Sender(*signer)
|
|
|
|
}
|
2020-08-01 07:39:04 +00:00
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
2021-04-18 05:05:54 +00:00
|
|
|
"blockHash": receipt.BlockHash,
|
|
|
|
"blockNumber": hexutil.Uint64(receipt.BlockNumber.Uint64()),
|
2022-07-09 03:15:22 +00:00
|
|
|
"transactionHash": txnHash,
|
2021-04-18 05:05:54 +00:00
|
|
|
"transactionIndex": hexutil.Uint64(receipt.TransactionIndex),
|
2020-08-01 07:39:04 +00:00
|
|
|
"from": from,
|
2021-04-22 17:11:37 +00:00
|
|
|
"to": txn.GetTo(),
|
2021-04-18 05:05:54 +00:00
|
|
|
"type": hexutil.Uint(txn.Type()),
|
2020-08-01 07:39:04 +00:00
|
|
|
"gasUsed": hexutil.Uint64(receipt.GasUsed),
|
|
|
|
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
|
|
|
|
"contractAddress": nil,
|
|
|
|
"logs": receipt.Logs,
|
2020-09-28 17:18:36 +00:00
|
|
|
"logsBloom": types.CreateBloom(types.Receipts{receipt}),
|
2020-08-01 07:39:04 +00:00
|
|
|
}
|
|
|
|
|
2021-06-30 02:50:39 +00:00
|
|
|
if !chainConfig.IsLondon(block.NumberU64()) {
|
|
|
|
fields["effectiveGasPrice"] = hexutil.Uint64(txn.GetPrice().Uint64())
|
|
|
|
} else {
|
|
|
|
baseFee, _ := uint256.FromBig(block.BaseFee())
|
|
|
|
gasPrice := new(big.Int).Add(block.BaseFee(), txn.GetEffectiveGasTip(baseFee).ToBig())
|
|
|
|
fields["effectiveGasPrice"] = hexutil.Uint64(gasPrice.Uint64())
|
|
|
|
}
|
2021-06-23 14:52:31 +00:00
|
|
|
// Assign receipt status.
|
2021-06-30 11:56:00 +00:00
|
|
|
fields["status"] = hexutil.Uint64(receipt.Status)
|
2020-08-01 07:39:04 +00:00
|
|
|
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
|
|
|
|
}
|
2021-04-18 05:05:54 +00:00
|
|
|
return fields
|
2020-08-01 07:39:04 +00:00
|
|
|
}
|
2020-09-03 07:51:19 +00:00
|
|
|
|
|
|
|
func includes(addresses []common.Address, a common.Address) bool {
|
|
|
|
for _, addr := range addresses {
|
|
|
|
if addr == a {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// filterLogs creates a slice of logs matching the given criteria.
|
2021-06-23 22:33:45 +00:00
|
|
|
func filterLogs(logs []*types.Log, addresses []common.Address, topics [][]common.Hash) []*types.Log {
|
2022-03-25 04:17:23 +00:00
|
|
|
result := make(types.Logs, 0, len(logs))
|
2020-09-03 07:51:19 +00:00
|
|
|
Logs:
|
|
|
|
for _, log := range logs {
|
|
|
|
|
|
|
|
if len(addresses) > 0 && !includes(addresses, log.Address) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// If the to filtered topics is greater than the amount of topics in logs, skip.
|
|
|
|
if len(topics) > len(log.Topics) {
|
|
|
|
continue Logs
|
|
|
|
}
|
|
|
|
for i, sub := range topics {
|
|
|
|
match := len(sub) == 0 // empty rule set == wildcard
|
|
|
|
for _, topic := range sub {
|
|
|
|
if log.Topics[i] == topic {
|
|
|
|
match = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !match {
|
|
|
|
continue Logs
|
|
|
|
}
|
|
|
|
}
|
2022-03-25 04:17:23 +00:00
|
|
|
result = append(result, log)
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|
2022-03-25 04:17:23 +00:00
|
|
|
return result
|
2020-09-03 07:51:19 +00:00
|
|
|
}
|