@@ -3,20 +3,30 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'
3
3
import _ from 'lodash' ;
4
4
import { Logger } from 'pino' ;
5
5
6
- import { nanOrNumberTo0x , nullableNumberTo0x , numberTo0x , toHash32 } from '../../../../formatters' ;
6
+ import { nanOrNumberTo0x , numberTo0x } from '../../../../formatters' ;
7
7
import { IReceiptRootHash , ReceiptsRootUtils } from '../../../../receiptsRootUtils' ;
8
8
import { Utils } from '../../../../utils' ;
9
9
import { MirrorNodeClient } from '../../../clients/mirrorNodeClient' ;
10
10
import constants from '../../../constants' ;
11
11
import { predefined } from '../../../errors/JsonRpcError' ;
12
12
import { BlockFactory } from '../../../factories/blockFactory' ;
13
13
import { TransactionFactory } from '../../../factories/transactionFactory' ;
14
- import { Block , Log , Receipt , Transaction } from '../../../model' ;
15
- import { IContractResultsParams , MirrorNodeBlock , RequestDetails } from '../../../types' ;
14
+ import {
15
+ IRegularTransactionReceiptParams ,
16
+ TransactionReceiptFactory ,
17
+ } from '../../../factories/transactionReceiptFactory' ;
18
+ import { Block , Log , Transaction } from '../../../model' ;
19
+ import { IContractResultsParams , ITransactionReceipt , MirrorNodeBlock , RequestDetails } from '../../../types' ;
20
+ import { CacheService } from '../../cacheService/cacheService' ;
16
21
import { IBlockService , ICommonService } from '../../index' ;
17
22
import { CommonService } from '../ethCommonService/CommonService' ;
18
-
19
23
export class BlockService implements IBlockService {
24
+ /**
25
+ * The cache service used for caching all responses.
26
+ * @private
27
+ */
28
+ private readonly cacheService : CacheService ;
29
+
20
30
/**
21
31
* The chain id.
22
32
* @private
@@ -47,7 +57,14 @@ export class BlockService implements IBlockService {
47
57
private readonly mirrorNodeClient : MirrorNodeClient ;
48
58
49
59
/** Constructor */
50
- constructor ( chain : string , common : ICommonService , mirrorNodeClient : MirrorNodeClient , logger : Logger ) {
60
+ constructor (
61
+ cacheService : CacheService ,
62
+ chain : string ,
63
+ common : ICommonService ,
64
+ mirrorNodeClient : MirrorNodeClient ,
65
+ logger : Logger ,
66
+ ) {
67
+ this . cacheService = cacheService ;
51
68
this . chain = chain ;
52
69
this . common = common ;
53
70
this . mirrorNodeClient = mirrorNodeClient ;
@@ -106,13 +123,28 @@ export class BlockService implements IBlockService {
106
123
* @param {RequestDetails } requestDetails The request details for logging and tracking
107
124
* @returns {Promise<Receipt[]> } Array of transaction receipts for the block
108
125
*/
109
- public async getBlockReceipts ( blockHashOrBlockNumber : string , requestDetails : RequestDetails ) : Promise < Receipt [ ] > {
126
+ public async getBlockReceipts (
127
+ blockHashOrBlockNumber : string ,
128
+ requestDetails : RequestDetails ,
129
+ ) : Promise < ITransactionReceipt [ ] > {
110
130
const requestIdPrefix = requestDetails . formattedRequestId ;
111
131
if ( this . logger . isLevelEnabled ( 'trace' ) ) {
112
132
this . logger . trace ( `${ requestIdPrefix } getBlockReceipt(${ JSON . stringify ( blockHashOrBlockNumber ) } )` ) ;
113
133
}
114
134
115
135
const block = await this . common . getHistoricalBlockResponse ( requestDetails , blockHashOrBlockNumber ) ;
136
+
137
+ if ( block == null ) {
138
+ throw predefined . RESOURCE_NOT_FOUND ( `Block: ${ blockHashOrBlockNumber } ` ) ;
139
+ }
140
+
141
+ const blockNumber = block . number ;
142
+ const cacheKey = `${ constants . CACHE_KEY . ETH_GET_BLOCK_RECEIPTS } _${ blockNumber } ` ;
143
+ const cachedResponse = await this . cacheService . getAsync ( cacheKey , constants . ETH_GET_BLOCK_RECEIPTS , requestDetails ) ;
144
+ if ( cachedResponse ) {
145
+ return cachedResponse ;
146
+ }
147
+
116
148
const paramTimestamp : IContractResultsParams = {
117
149
timestamp : [ `lte:${ block . timestamp . to } ` , `gte:${ block . timestamp . from } ` ] ,
118
150
} ;
@@ -122,39 +154,56 @@ export class BlockService implements IBlockService {
122
154
return [ ] ;
123
155
}
124
156
125
- const effectiveGas = await this . common . getCurrentGasPriceForBlock ( block . hash , requestDetails ) ;
157
+ const receipts : ITransactionReceipt [ ] = [ ] ;
158
+ const effectiveGas = numberTo0x ( await this . common . getGasPriceInWeibars ( block . timestamp . from . split ( '.' ) [ 0 ] ) ) ;
126
159
127
160
const logs = await this . common . getLogsWithParams ( null , paramTimestamp , requestDetails ) ;
128
- contractResults . forEach ( ( contractResult ) => {
129
- contractResult . logs = logs . filter ( ( log ) => log . transactionHash === contractResult . hash ) ;
130
- } ) ;
131
161
132
- const receipts : Receipt [ ] = [ ] ;
162
+ const logsByHash = new Map < string , Log [ ] > ( ) ;
163
+ for ( const log of logs ) {
164
+ const existingLogs = logsByHash . get ( log . transactionHash ) || [ ] ;
165
+ existingLogs . push ( log ) ;
166
+ logsByHash . set ( log . transactionHash , existingLogs ) ;
167
+ }
133
168
134
- for ( const contractResult of contractResults ) {
135
- const from = await this . common . resolveEvmAddress ( contractResult . from , requestDetails ) ;
136
- const to = await this . common . resolveEvmAddress ( contractResult . to , requestDetails ) ;
137
-
138
- const contractAddress = this . common . getContractAddressFromReceipt ( contractResult ) ;
139
- const receipt = {
140
- blockHash : toHash32 ( contractResult . block_hash ) ,
141
- blockNumber : numberTo0x ( contractResult . block_number ) ,
142
- from : from ,
143
- to : to ,
144
- cumulativeGasUsed : numberTo0x ( contractResult . block_gas_used ) ,
145
- gasUsed : nanOrNumberTo0x ( contractResult . gas_used ) ,
146
- contractAddress : contractAddress ,
169
+ const receiptPromises = contractResults . map ( async ( contractResult ) => {
170
+ if ( Utils . isRevertedDueToHederaSpecificValidation ( contractResult ) ) {
171
+ if ( this . logger . isLevelEnabled ( 'debug' ) ) {
172
+ this . logger . debug (
173
+ `${ requestIdPrefix } Transaction with hash ${ contractResult . hash } is skipped due to hedera-specific validation failure (${ contractResult . result } )` ,
174
+ ) ;
175
+ }
176
+ return null ;
177
+ }
178
+ contractResult . logs = logsByHash . get ( contractResult . hash ) || [ ] ;
179
+ const [ from , to ] = await Promise . all ( [
180
+ this . common . resolveEvmAddress ( contractResult . from , requestDetails ) ,
181
+ this . common . resolveEvmAddress ( contractResult . to , requestDetails ) ,
182
+ ] ) ;
183
+ const transactionReceiptParams : IRegularTransactionReceiptParams = {
184
+ effectiveGas,
185
+ from,
147
186
logs : contractResult . logs ,
148
- logsBloom : contractResult . bloom === constants . EMPTY_HEX ? constants . EMPTY_BLOOM : contractResult . bloom ,
149
- transactionHash : toHash32 ( contractResult . hash ) ,
150
- transactionIndex : numberTo0x ( contractResult . transaction_index ) ,
151
- effectiveGasPrice : effectiveGas ,
152
- root : contractResult . root || constants . DEFAULT_ROOT_HASH ,
153
- status : contractResult . status ,
154
- type : nullableNumberTo0x ( contractResult . type ) ,
187
+ receiptResponse : contractResult ,
188
+ to,
155
189
} ;
190
+ return TransactionReceiptFactory . createRegularReceipt ( transactionReceiptParams ) as ITransactionReceipt ;
191
+ } ) ;
192
+
193
+ const resolvedReceipts = await Promise . all ( receiptPromises ) ;
194
+ receipts . push ( ...resolvedReceipts . filter ( Boolean ) ) ;
156
195
157
- receipts . push ( receipt ) ;
196
+ const regularTxHashes = new Set ( contractResults . map ( ( result ) => result . hash ) ) ;
197
+
198
+ // filtering out the synthetic tx hashes and creating the synthetic receipt
199
+ for ( const [ txHash , logGroup ] of logsByHash . entries ( ) ) {
200
+ if ( ! regularTxHashes . has ( txHash ) ) {
201
+ const syntheticReceipt = TransactionReceiptFactory . createSyntheticReceipt ( {
202
+ syntheticLogs : logGroup ,
203
+ gasPriceForTimestamp : effectiveGas ,
204
+ } ) ;
205
+ receipts . push ( syntheticReceipt as ITransactionReceipt ) ;
206
+ }
158
207
}
159
208
160
209
return receipts ;
0 commit comments