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 }