From 936f1e968c3c26224050876061f9329c2eaa2550 Mon Sep 17 00:00:00 2001 From: Logan Nguyen Date: Fri, 20 Dec 2024 20:07:12 -0600 Subject: [PATCH] fix: added getContractResultsLogsWithRetry() Signed-off-by: Logan Nguyen --- .../relay/src/lib/clients/mirrorNodeClient.ts | 41 +++++++++++++++++-- .../ethService/ethCommonService/index.ts | 2 +- .../relay/tests/lib/mirrorNodeClient.spec.ts | 2 +- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/packages/relay/src/lib/clients/mirrorNodeClient.ts b/packages/relay/src/lib/clients/mirrorNodeClient.ts index 5755600baf..8aeb6e6346 100644 --- a/packages/relay/src/lib/clients/mirrorNodeClient.ts +++ b/packages/relay/src/lib/clients/mirrorNodeClient.ts @@ -894,14 +894,25 @@ export class MirrorNodeClient { return this.getQueryParams(queryParamObject); } - public async getContractResultsLogs( + /** + * In some very rare cases the /contracts/results/logs api is called before all the data is saved in + * the mirror node DB and `transaction_index`, `block_number`, or `index` is returned as `undefined`. + * A single re-fetch is sufficient to resolve this problem. + * + * @param {RequestDetails} requestDetails - Details used for logging and tracking the request. + * @param {IContractLogsResultsParams} [contractLogsResultsParams] - Parameters for querying contract logs results. + * @param {ILimitOrderParams} [limitOrderParams] - Parameters for limit and order when fetching the logs. + * @returns {Promise} - A promise resolving to the paginated contract logs results. + */ + public async getContractResultsLogsWithRetry( requestDetails: RequestDetails, contractLogsResultsParams?: IContractLogsResultsParams, limitOrderParams?: ILimitOrderParams, - ) { + ): Promise { + const shortDelay = 250; const queryParams = this.prepareLogsParams(contractLogsResultsParams, limitOrderParams); - return this.getPaginatedResults( + const logResults = await this.getPaginatedResults( `${MirrorNodeClient.GET_CONTRACT_RESULT_LOGS_ENDPOINT}${queryParams}`, MirrorNodeClient.GET_CONTRACT_RESULT_LOGS_ENDPOINT, MirrorNodeClient.CONTRACT_RESULT_LOGS_PROPERTY, @@ -910,6 +921,30 @@ export class MirrorNodeClient { 1, MirrorNodeClient.mirrorNodeContractResultsLogsPageMax, ); + + for (const log of logResults) { + if (log && !(log.transaction_index && log.block_number && log.index)) { + if (this.logger.isLevelEnabled('debug')) { + this.logger.debug( + `${requestDetails.formattedRequestId} Contract result log contains undefined transaction_index, block_number, or index. Retrying after a delay of ${shortDelay} ms.`, + ); + } + + // Backoff before repeating request + await new Promise((r) => setTimeout(r, shortDelay)); + return this.getPaginatedResults( + `${MirrorNodeClient.GET_CONTRACT_RESULT_LOGS_ENDPOINT}${queryParams}`, + MirrorNodeClient.GET_CONTRACT_RESULT_LOGS_ENDPOINT, + MirrorNodeClient.CONTRACT_RESULT_LOGS_PROPERTY, + requestDetails, + [], + 1, + MirrorNodeClient.mirrorNodeContractResultsLogsPageMax, + ); + } + } + + return logResults; } public async getContractResultsLogsByAddress( diff --git a/packages/relay/src/lib/services/ethService/ethCommonService/index.ts b/packages/relay/src/lib/services/ethService/ethCommonService/index.ts index 34ad70cad4..de7ef85152 100644 --- a/packages/relay/src/lib/services/ethService/ethCommonService/index.ts +++ b/packages/relay/src/lib/services/ethService/ethCommonService/index.ts @@ -322,7 +322,7 @@ export class CommonService implements ICommonService { if (address) { logResults = await this.getLogsByAddress(address, params, requestDetails); } else { - logResults = await this.mirrorNodeClient.getContractResultsLogs(requestDetails, params); + logResults = await this.mirrorNodeClient.getContractResultsLogsWithRetry(requestDetails, params); } if (!logResults) { diff --git a/packages/relay/tests/lib/mirrorNodeClient.spec.ts b/packages/relay/tests/lib/mirrorNodeClient.spec.ts index 7d80e75936..9b500d495b 100644 --- a/packages/relay/tests/lib/mirrorNodeClient.spec.ts +++ b/packages/relay/tests/lib/mirrorNodeClient.spec.ts @@ -795,7 +795,7 @@ describe('MirrorNodeClient', async function () { it('`getContractResultsLogs` ', async () => { mock.onGet(`contracts/results/logs?limit=100&order=asc`).reply(200, { logs: [log] }); - const results = await mirrorNodeInstance.getContractResultsLogs(requestDetails); + const results = await mirrorNodeInstance.getContractResultsLogsWithRetry(requestDetails); expect(results).to.exist; expect(results.length).to.gt(0); const firstResult = results[0];