1- /*-
1+ /* -
22 *
33 * Hedera JSON RPC Relay
44 *
1818 *
1919 */
2020
21- import Axios , { AxiosInstance , AxiosRequestConfig } from 'axios' ;
22- import { MirrorNodeClientError } from './. ./errors/MirrorNodeClientError' ;
21+ import Axios , { AxiosInstance , AxiosRequestConfig , AxiosResponse } from 'axios' ;
22+ import { MirrorNodeClientError } from '../errors/MirrorNodeClientError' ;
2323import { Logger } from 'pino' ;
2424import constants from './../constants' ;
2525import { Histogram , Registry } from 'prom-client' ;
@@ -31,8 +31,9 @@ import { install as betterLookupInstall } from 'better-lookup';
3131import { CacheService } from '../services/cacheService/cacheService' ;
3232import { ethers } from 'ethers' ;
3333
34- const http = require ( 'http' ) ;
35- const https = require ( 'https' ) ;
34+ import http from 'http' ;
35+ import https from 'https' ;
36+ import { IOpcodesResponse } from './models/IOpcodesResponse' ;
3637
3738type REQUEST_METHODS = 'GET' | 'POST' ;
3839
@@ -73,6 +74,7 @@ export class MirrorNodeClient {
7374 private static GET_CONTRACT_RESULTS_DETAILS_BY_ADDRESS_AND_TIMESTAMP_ENDPOINT = `contracts/${ MirrorNodeClient . ADDRESS_PLACEHOLDER } /results/${ MirrorNodeClient . TIMESTAMP_PLACEHOLDER } ` ;
7475 private static GET_CONTRACT_RESULTS_DETAILS_BY_CONTRACT_ID_ENDPOINT = `contracts/${ MirrorNodeClient . CONTRACT_ID_PLACEHOLDER } /results/${ MirrorNodeClient . TIMESTAMP_PLACEHOLDER } ` ;
7576 private static GET_CONTRACTS_RESULTS_ACTIONS = `contracts/results/${ MirrorNodeClient . TRANSACTION_ID_PLACEHOLDER } /actions` ;
77+ private static GET_CONTRACTS_RESULTS_OPCODES = `contracts/results/${ MirrorNodeClient . TRANSACTION_ID_PLACEHOLDER } /opcodes` ;
7678 private static GET_CONTRACT_RESULT_ENDPOINT = 'contracts/results/' ;
7779 private static GET_CONTRACT_RESULT_LOGS_ENDPOINT = 'contracts/results/logs' ;
7880 private static GET_CONTRACT_RESULT_LOGS_BY_ADDRESS_ENDPOINT = `contracts/${ MirrorNodeClient . ADDRESS_PLACEHOLDER } /results/logs` ;
@@ -103,6 +105,7 @@ export class MirrorNodeClient {
103105 [ MirrorNodeClient . GET_CONTRACT_RESULT_LOGS_ENDPOINT , [ 404 ] ] ,
104106 [ MirrorNodeClient . GET_CONTRACT_RESULT_LOGS_BY_ADDRESS_ENDPOINT , [ 404 ] ] ,
105107 [ MirrorNodeClient . GET_CONTRACT_RESULTS_ENDPOINT , [ 404 ] ] ,
108+ [ MirrorNodeClient . GET_CONTRACTS_RESULTS_OPCODES , [ 404 ] ] ,
106109 [ MirrorNodeClient . GET_NETWORK_EXCHANGERATE_ENDPOINT , [ 404 ] ] ,
107110 [ MirrorNodeClient . GET_NETWORK_FEES_ENDPOINT , [ 404 ] ] ,
108111 [ MirrorNodeClient . GET_TOKENS_ENDPOINT , [ 404 ] ] ,
@@ -149,9 +152,18 @@ export class MirrorNodeClient {
149152 */
150153 private readonly register : Registry ;
151154
152- private mirrorResponseHistogram ;
155+ /**
156+ * The histogram used for tracking the response time of the mirror node.
157+ * @private
158+ */
159+ private readonly mirrorResponseHistogram : Histogram ;
153160
161+ /**
162+ * The cache service used for caching responses.
163+ * @private
164+ */
154165 private readonly cacheService : CacheService ;
166+
155167 static readonly EVM_ADDRESS_REGEX : RegExp = / \/ a c c o u n t s \/ ( [ \d \. ] + ) / ;
156168
157169 static mirrorNodeContractResultsPageMax = parseInt ( process . env . MIRROR_NODE_CONTRACT_RESULTS_PG_MAX ! ) || 25 ;
@@ -304,26 +316,23 @@ export class MirrorNodeClient {
304316 return `${ baseUrl } ${ MirrorNodeClient . API_V1_POST_FIX } ` ;
305317 }
306318
307- private async request (
319+ private async request < T > (
308320 path : string ,
309321 pathLabel : string ,
310322 method : REQUEST_METHODS ,
311323 data ?: any ,
312324 requestIdPrefix ?: string ,
313325 retries ?: number ,
314- ) : Promise < any > {
326+ ) : Promise < T | null > {
315327 const start = Date . now ( ) ;
316328 // extract request id from prefix and remove trailing ']' character
317329 const requestId =
318330 requestIdPrefix
319331 ?. split ( MirrorNodeClient . REQUEST_PREFIX_SEPARATOR ) [ 1 ]
320332 . replace ( MirrorNodeClient . REQUEST_PREFIX_TRAILING_BRACKET , MirrorNodeClient . EMPTY_STRING ) ||
321333 MirrorNodeClient . EMPTY_STRING ;
322- let ms ;
323334 const controller = new AbortController ( ) ;
324335 try {
325- let response ;
326-
327336 const axiosRequestConfig : AxiosRequestConfig = {
328337 headers : {
329338 [ MirrorNodeClient . REQUESTID_LABEL ] : requestId ,
@@ -336,18 +345,23 @@ export class MirrorNodeClient {
336345 axiosRequestConfig [ 'axios-retry' ] = { retries } ;
337346 }
338347
348+ let response : AxiosResponse < T , any > ;
339349 if ( method === MirrorNodeClient . HTTP_GET ) {
340- response = await this . restClient . get ( path , axiosRequestConfig ) ;
350+ if ( pathLabel == MirrorNodeClient . GET_CONTRACTS_RESULTS_OPCODES ) {
351+ response = await this . web3Client . get < T > ( path , axiosRequestConfig ) ;
352+ } else {
353+ response = await this . restClient . get < T > ( path , axiosRequestConfig ) ;
354+ }
341355 } else {
342- response = await this . web3Client . post ( path , data , axiosRequestConfig ) ;
356+ response = await this . web3Client . post < T > ( path , data , axiosRequestConfig ) ;
343357 }
344358
345359 const ms = Date . now ( ) - start ;
346360 this . logger . debug ( `${ requestId } [${ method } ] ${ path } ${ response . status } ${ ms } ms` ) ;
347- this . mirrorResponseHistogram . labels ( pathLabel , response . status ) . observe ( ms ) ;
361+ this . mirrorResponseHistogram . labels ( pathLabel , response . status ?. toString ( ) ) . observe ( ms ) ;
348362 return response . data ;
349363 } catch ( error : any ) {
350- ms = Date . now ( ) - start ;
364+ const ms = Date . now ( ) - start ;
351365 const effectiveStatusCode =
352366 error . response ?. status ||
353367 MirrorNodeClientError . ErrorCodes [ error . code ] ||
@@ -363,15 +377,25 @@ export class MirrorNodeClient {
363377 return null ;
364378 }
365379
366- async get ( path : string , pathLabel : string , requestIdPrefix ?: string , retries ?: number ) : Promise < any > {
367- return this . request ( path , pathLabel , 'GET' , null , requestIdPrefix , retries ) ;
380+ async get < T = any > ( path : string , pathLabel : string , requestIdPrefix ?: string , retries ?: number ) : Promise < T | null > {
381+ return this . request < T > ( path , pathLabel , 'GET' , null , requestIdPrefix , retries ) ;
368382 }
369383
370- async post ( path : string , data : any , pathLabel : string , requestIdPrefix ?: string , retries ?: number ) : Promise < any > {
384+ async post < T = any > (
385+ path : string ,
386+ data : any ,
387+ pathLabel : string ,
388+ requestIdPrefix ?: string ,
389+ retries ?: number ,
390+ ) : Promise < T | null > {
371391 if ( ! data ) data = { } ;
372- return this . request ( path , pathLabel , 'POST' , data , requestIdPrefix , retries ) ;
392+ return this . request < T > ( path , pathLabel , 'POST' , data , requestIdPrefix , retries ) ;
373393 }
374394
395+ /**
396+ * @returns null if the error code is in the accepted error responses,
397+ * @throws MirrorNodeClientError if the error code is not in the accepted error responses.
398+ */
375399 handleError (
376400 error : any ,
377401 path : string ,
@@ -383,7 +407,7 @@ export class MirrorNodeClient {
383407 const mirrorError = new MirrorNodeClientError ( error , effectiveStatusCode ) ;
384408 const acceptedErrorResponses = MirrorNodeClient . acceptedErrorStatusesResponsePerRequestPathMap . get ( pathLabel ) ;
385409
386- if ( error . response && acceptedErrorResponses && acceptedErrorResponses . indexOf ( effectiveStatusCode ) !== - 1 ) {
410+ if ( error . response && acceptedErrorResponses ?. includes ( effectiveStatusCode ) ) {
387411 this . logger . debug ( `${ requestIdPrefix } [${ method } ] ${ path } ${ effectiveStatusCode } status` ) ;
388412 return null ;
389413 }
@@ -699,7 +723,7 @@ export class MirrorNodeClient {
699723 * the mirror node DB and `transaction_index` or `block_number` is returned as `undefined`. A single re-fetch is sufficient to
700724 * resolve this problem.
701725 * @param transactionIdOrHash
702- * @param requestId
726+ * @param requestIdPrefix
703727 */
704728 public async getContractResultWithRetry ( transactionIdOrHash : string , requestIdPrefix ?: string ) {
705729 const contractResult = await this . getContractResult ( transactionIdOrHash , requestIdPrefix ) ;
@@ -745,6 +769,19 @@ export class MirrorNodeClient {
745769 ) ;
746770 }
747771
772+ public async getContractsResultsOpcodes (
773+ transactionIdOrHash : string ,
774+ requestIdPrefix ?: string ,
775+ params ?: { memory ?: boolean ; stack ?: boolean ; storage ?: boolean } ,
776+ ) : Promise < IOpcodesResponse | null > {
777+ const queryParams = params ? this . getQueryParams ( params ) : '' ;
778+ return this . get < IOpcodesResponse > (
779+ `${ this . getContractResultsOpcodesByTransactionIdPath ( transactionIdOrHash ) } ${ queryParams } ` ,
780+ MirrorNodeClient . GET_CONTRACTS_RESULTS_OPCODES ,
781+ requestIdPrefix ,
782+ ) ;
783+ }
784+
748785 public async getContractResultsByAddress (
749786 contractIdOrAddress : string ,
750787 contractResultsParams ?: IContractResultsParams ,
@@ -928,6 +965,13 @@ export class MirrorNodeClient {
928965 ) ;
929966 }
930967
968+ private getContractResultsOpcodesByTransactionIdPath ( transactionIdOrHash : string ) {
969+ return MirrorNodeClient . GET_CONTRACTS_RESULTS_OPCODES . replace (
970+ MirrorNodeClient . TRANSACTION_ID_PLACEHOLDER ,
971+ transactionIdOrHash ,
972+ ) ;
973+ }
974+
931975 public async getTokenById ( tokenId : string , requestIdPrefix ?: string , retries ?: number ) {
932976 return this . get (
933977 `${ MirrorNodeClient . GET_TOKENS_ENDPOINT } /${ tokenId } ` ,
@@ -1009,7 +1053,6 @@ export class MirrorNodeClient {
10091053 * Check if transaction fail is because of contract revert and try to fetch and log the reason.
10101054 *
10111055 * @param e
1012- * @param requestId
10131056 * @param requestIdPrefix
10141057 */
10151058 public async getContractRevertReasonFromTransaction ( e : any , requestIdPrefix : string ) : Promise < any | undefined > {
@@ -1087,6 +1130,7 @@ export class MirrorNodeClient {
10871130 * @param searchableTypes the types to search for
10881131 * @param callerName calling method name
10891132 * @param requestIdPrefix the request id prefix message
1133+ * @param retries the number of retries
10901134 * @returns entity object or null if not found
10911135 */
10921136 public async resolveEntityType (
0 commit comments