github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/rpc/get_receipt.go (about)

     1  // Copyright 2021 The TrueBlocks Authors. All rights reserved.
     2  // Use of this source code is governed by a license that can
     3  // be found in the LICENSE file.
     4  
     5  package rpc
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    11  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc/query"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    14  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    15  )
    16  
    17  // GetReceipt retrieves a single receipt by block number and transaction id. If suggested is provided,
    18  // it will be used for the timestamp of the logs.
    19  func (conn *Connection) GetReceipt(bn base.Blknum, txid base.Txnum, suggested base.Timestamp) (receipt types.Receipt, err error) {
    20  	receipt, err = conn.GetReceiptNoTimestamp(bn, txid) // note that the logs do not yet have timestamp...
    21  
    22  	if suggested == 0 {
    23  		suggested = conn.GetBlockTimestamp(bn)
    24  	}
    25  	for index := 0; index < len(receipt.Logs); index++ {
    26  		receipt.Logs[index].Timestamp = suggested
    27  	}
    28  
    29  	return receipt, err
    30  }
    31  
    32  // GetReceiptNoTimestamp fetches receipt from the RPC. If txGasPrice is provided, it will be used for
    33  // receipts in blocks before London
    34  func (conn *Connection) GetReceiptNoTimestamp(bn base.Blknum, txid base.Txnum) (receipt types.Receipt, err error) {
    35  	if conn.StoreReadable() {
    36  		// walk.Cache_Transactions
    37  		tx := &types.Transaction{
    38  			BlockNumber:      bn,
    39  			TransactionIndex: txid,
    40  		}
    41  		if err := conn.Store.Read(tx, nil); err == nil {
    42  			// success
    43  			if tx.Receipt == nil {
    44  				return receipt, nil
    45  			}
    46  			return *tx.Receipt, nil
    47  		}
    48  	}
    49  
    50  	// TODO: Bogus - weird code related to with or without timestamp. There's a better way
    51  	return conn.getReceiptFromRpc(bn, txid)
    52  }
    53  
    54  // getReceiptFromRpc fetches transaction given blockNumber and transactionIndex
    55  func (conn *Connection) getReceiptFromRpc(bn base.Blknum, txid base.Txnum) (receipt types.Receipt, err error) {
    56  	if txHash, err := conn.GetTransactionHashByNumberAndID(bn, txid); err != nil {
    57  		return types.Receipt{}, err
    58  
    59  	} else {
    60  		method := "eth_getTransactionReceipt"
    61  		params := query.Params{txHash}
    62  
    63  		if receipt, err := query.Query[types.Receipt](conn.Chain, method, params); err != nil {
    64  			return types.Receipt{}, err
    65  		} else {
    66  			receipt.IsError = receipt.Status == 0
    67  			return *receipt, nil
    68  		}
    69  	}
    70  }
    71  
    72  // GetReceiptsByNumber returns all receipts in a blocks along with their logs
    73  func (conn *Connection) GetReceiptsByNumber(bn base.Blknum, ts base.Timestamp) ([]types.Receipt, map[base.Txnum]*types.Receipt, error) {
    74  	if conn.StoreReadable() {
    75  		// walk.Cache_Receipts
    76  		receiptGroup := &types.ReceiptGroup{
    77  			BlockNumber:      bn,
    78  			TransactionIndex: base.NOPOSN,
    79  		}
    80  		if err := conn.Store.Read(receiptGroup, nil); err == nil {
    81  			receiptMap := make(map[base.Txnum]*types.Receipt, len(receiptGroup.Receipts))
    82  			for index := 0; index < len(receiptGroup.Receipts); index++ {
    83  				pReceipt := &receiptGroup.Receipts[index]
    84  				receiptMap[pReceipt.TransactionIndex] = pReceipt
    85  			}
    86  			return receiptGroup.Receipts, receiptMap, nil
    87  		}
    88  	}
    89  
    90  	if receipts, err := conn.getBlockReceiptsFromRpc(bn); err != nil {
    91  		return receipts, nil, err
    92  	} else {
    93  		isFinal := base.IsFinal(conn.LatestBlockTimestamp, ts)
    94  		if isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Receipts] {
    95  			receiptGroup := &types.ReceiptGroup{
    96  				BlockNumber:      bn,
    97  				TransactionIndex: base.NOPOSN,
    98  				Receipts:         receipts,
    99  			}
   100  			if err = conn.Store.Write(receiptGroup, nil); err != nil {
   101  				logger.Warn("Failed to write receipts to cache", err)
   102  			}
   103  		}
   104  
   105  		receiptMap := make(map[base.Txnum]*types.Receipt, len(receipts))
   106  		for index := 0; index < len(receipts); index++ {
   107  			pReceipt := &receipts[index]
   108  			receiptMap[pReceipt.TransactionIndex] = pReceipt
   109  		}
   110  		return receipts, receiptMap, err
   111  	}
   112  }
   113  
   114  // getBlockReceiptsFromRpc fetches receipts from the RPC using eth_getBlockReceipts. It returns
   115  // an array of Receipts with the timestamp set to the block timestamp.
   116  func (conn *Connection) getBlockReceiptsFromRpc(bn base.Blknum) ([]types.Receipt, error) {
   117  	method := "eth_getBlockReceipts"
   118  	params := query.Params{fmt.Sprintf("0x%x", bn)}
   119  
   120  	if receipts, err := query.Query[[]types.Receipt](conn.Chain, method, params); err != nil {
   121  		return []types.Receipt{}, err
   122  
   123  	} else if receipts == nil || len(*receipts) == 0 {
   124  		return []types.Receipt{}, nil
   125  
   126  	} else {
   127  		var ret []types.Receipt
   128  		for _, receipt := range *receipts {
   129  			receipt.IsError = receipt.Status == 0
   130  			ret = append(ret, receipt)
   131  		}
   132  		return ret, nil
   133  	}
   134  }