From 5095986a07feeb53ac9b74afed9d9ce3149b876a Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Tue, 9 May 2023 10:40:29 +0200 Subject: [PATCH 1/6] fix(integration-tests): unskip tests --- packages/integration-test/test/node-client.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration-test/test/node-client.test.ts b/packages/integration-test/test/node-client.test.ts index a070ea72be..9c99c5f7e9 100644 --- a/packages/integration-test/test/node-client.test.ts +++ b/packages/integration-test/test/node-client.test.ts @@ -538,7 +538,7 @@ describe('ERC20 localhost request creation and detection test', () => { expect(requestData.pending).toBeNull(); }); - it.only('can create ERC20 requests with any to erc20 proxy', async () => { + it('can create ERC20 requests with any to erc20 proxy', async () => { const tokenContractAddress = '0x38cF23C52Bb4B13F051Aec09580a2dE845a7FA35'; const currencies: CurrencyInput[] = [ From a7b9eb2c84da2ebe2c3181b8303507a1ed91e51b Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Thu, 11 May 2023 21:40:49 +0200 Subject: [PATCH 2/6] fix integration tests --- .../integration-test/test/node-client.test.ts | 58 ++++++++++++++----- .../src/request/confirmedTransactionStore.ts | 2 +- .../src/request/persistTransaction.ts | 2 +- .../thegraph-data-access/src/data-access.ts | 4 +- packages/utils/src/retry.ts | 2 +- 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/packages/integration-test/test/node-client.test.ts b/packages/integration-test/test/node-client.test.ts index 9c99c5f7e9..7049f13058 100644 --- a/packages/integration-test/test/node-client.test.ts +++ b/packages/integration-test/test/node-client.test.ts @@ -30,7 +30,7 @@ const provider = new providers.JsonRpcProvider('http://localhost:8545'); const wallet = Wallet.fromMnemonic(mnemonic).connect(provider); // eslint-disable-next-line no-magic-numbers -jest.setTimeout(10000); +jest.setTimeout(30000); const requestCreationHashBTC: Types.IRequestInfo = { currency: 'BTC', @@ -71,12 +71,38 @@ const wrongDecryptionProvider = new EthereumPrivateKeyDecryptionProvider({ method: Types.Encryption.METHOD.ECIES, }); +const waitForConfirmation = async (input: Request | Types.IRequestDataWithEvents) => { + // create the promise to wait for confirmation + let waitForConfirmationPromise: Promise; + if ('waitForConfirmation' in input) { + waitForConfirmationPromise = input.waitForConfirmation(); + } else { + waitForConfirmationPromise = new Promise((resolve) => input.on('confirmed', resolve)); + } + + // in parallel, mine an empty block, because a confirmation needs to wait for two blocks + // (the block that persisted the action + another block) + const mineBlockPromise = provider.send('evm_mine', []); + + // set a time limit to wait for confirmation before throwing + const timeoutError = new Error('waiting for confirmation took too long'); + const timeout = setTimeout(() => { + throw timeoutError; + }, 5000); + + // return the confirmation result + const promiseResults = await Promise.all([waitForConfirmationPromise, mineBlockPromise]); + clearTimeout(timeout); + return promiseResults[0]; +}; + describe('Request client using a request node', () => { it('can create a request, change the amount and get data', async () => { // Create a request const request = await requestNetwork.createRequest({ requestInfo: requestCreationHashBTC, signer: payeeIdentity, + disableEvents: false, }); expect(request).toBeInstanceOf(Request); expect(request.requestId).toBeDefined(); @@ -89,7 +115,7 @@ describe('Request client using a request node', () => { expect(requestData.meta).toBeDefined(); expect(requestData.pending!.state).toBe(Types.RequestLogic.STATE.CREATED); - requestData = await request.waitForConfirmation(); + requestData = await waitForConfirmation(request); expect(requestData.state).toBe(Types.RequestLogic.STATE.CREATED); expect(requestData.pending).toBeNull(); @@ -101,7 +127,7 @@ describe('Request client using a request node', () => { expect(requestData.meta).toBeDefined(); expect(requestData.pending!.expectedAmount).toBe('800'); - requestData = await new Promise((resolve) => requestData.on('confirmed', resolve)); + requestData = await waitForConfirmation(requestData); expect(requestData.expectedAmount).toBe('800'); expect(requestData.pending).toBeNull(); }); @@ -145,7 +171,7 @@ describe('Request client using a request node', () => { expect(extension.events[0].name).toBe('create'); expect(extension.events[0].parameters).toEqual(paymentNetwork.parameters); - requestData = await request.waitForConfirmation(); + requestData = await waitForConfirmation(request); expect(requestData.state).toBe(Types.RequestLogic.STATE.CREATED); expect(requestData.pending).toBeNull(); @@ -153,7 +179,7 @@ describe('Request client using a request node', () => { expect(requestData.balance).toBeDefined(); expect(requestData.balance!.balance).toBe('0'); - requestData = await new Promise((resolve) => requestData.on('confirmed', resolve)); + requestData = await waitForConfirmation(requestData); expect(requestData.balance!.balance).toBe('0'); requestData = await request.declareReceivedPayment( @@ -164,7 +190,7 @@ describe('Request client using a request node', () => { expect(requestData.balance).toBeDefined(); expect(requestData.balance!.balance).toBe('0'); - requestData = await new Promise((resolve) => requestData.on('confirmed', resolve)); + requestData = await waitForConfirmation(requestData); expect(requestData.balance!.balance).toBe('100'); }); @@ -187,7 +213,7 @@ describe('Request client using a request node', () => { signer: payeeIdentity, topics: topicsRequest1and2, }); - await request1.waitForConfirmation(); + await waitForConfirmation(request1); const timestampBeforeReduce = getCurrentTimestampInSecond(); // make sure that request 2 timestamp is greater than request 1 timestamp @@ -209,15 +235,15 @@ describe('Request client using a request node', () => { topics: topicsRequest1and2, }); - await request2.waitForConfirmation(); + await waitForConfirmation(request2); // reduce request 1 const requestDataReduce = await request1.reduceExpectedAmountRequest('10000000', payeeIdentity); - await new Promise((r) => requestDataReduce.on('confirmed', r)); + await waitForConfirmation(requestDataReduce); // cancel request 1 const requestDataCancel = await request1.cancel(payeeIdentity); - await new Promise((r) => requestDataCancel.on('confirmed', r)); + await waitForConfirmation(requestDataCancel); // get requests without boundaries let requests = await requestNetwork.fromTopic(topicsRequest1and2[0]); @@ -375,7 +401,7 @@ describe('Request client using a request node', () => { expect(requestData.pending!.state).toBe(Types.RequestLogic.STATE.CREATED); expect(requestData.meta!.transactionManagerMeta.encryptionMethod).toBe('ecies-aes256-gcm'); - await new Promise((resolve) => request.on('confirmed', resolve)); + await waitForConfirmation(request); // Fetch the created request by its id const fetchedRequest = await requestNetwork.fromRequestId(request.requestId); @@ -395,7 +421,7 @@ describe('Request client using a request node', () => { expect(fetchedRequestData.state).toBe(Types.RequestLogic.STATE.CREATED); const acceptData = await request.accept(payerIdentity); - await new Promise((resolve) => acceptData.on('confirmed', resolve)); + await waitForConfirmation(acceptData); await fetchedRequest.refresh(); fetchedRequestData = fetchedRequest.getData(); @@ -405,7 +431,7 @@ describe('Request client using a request node', () => { requestCreationHashBTC.expectedAmount, payerIdentity, ); - await new Promise((resolve) => increaseData.on('confirmed', resolve)); + await waitForConfirmation(increaseData); await fetchedRequest.refresh(); expect(fetchedRequest.getData().expectedAmount).toEqual( @@ -416,7 +442,7 @@ describe('Request client using a request node', () => { Number(requestCreationHashBTC.expectedAmount) * 2, payeeIdentity, ); - await new Promise((resolve) => reduceData.on('confirmed', resolve)); + await waitForConfirmation(reduceData); await fetchedRequest.refresh(); expect(fetchedRequest.getData().expectedAmount).toBe('0'); @@ -442,7 +468,7 @@ describe('Request client using a request node', () => { }, [encryptionData.encryptionParams], ); - await encryptedRequest.waitForConfirmation(); + await waitForConfirmation(encryptedRequest); // Create a plain request const plainRequest = await requestNetwork.createRequest({ @@ -533,7 +559,7 @@ describe('ERC20 localhost request creation and detection test', () => { expect(requestData.meta).toBeDefined(); expect(requestData.pending!.state).toBe(Types.RequestLogic.STATE.CREATED); - requestData = await new Promise((resolve) => request.on('confirmed', resolve)); + requestData = await waitForConfirmation(request); expect(requestData.state).toBe(Types.RequestLogic.STATE.CREATED); expect(requestData.pending).toBeNull(); }); diff --git a/packages/request-node/src/request/confirmedTransactionStore.ts b/packages/request-node/src/request/confirmedTransactionStore.ts index 6e65475e18..b48332f915 100644 --- a/packages/request-node/src/request/confirmedTransactionStore.ts +++ b/packages/request-node/src/request/confirmedTransactionStore.ts @@ -3,7 +3,7 @@ import Keyv, { Store } from 'keyv'; /** * Class for storing confirmed transactions information - * When 'confirmed' event is receive from a 'persistTransaction', the event data are stored. + * When 'confirmed' event is received from a 'persistTransaction', the event data are stored. * The client can call the getConfirmed entry point, to get the confirmed event. */ export default class ConfirmedTransactionStore { diff --git a/packages/request-node/src/request/persistTransaction.ts b/packages/request-node/src/request/persistTransaction.ts index 768e72244e..3cb2b63d27 100644 --- a/packages/request-node/src/request/persistTransaction.ts +++ b/packages/request-node/src/request/persistTransaction.ts @@ -71,7 +71,7 @@ export default class PersistTransactionHandler { clientRequest.body.topics, ); - // when the transaction is confirmed, store the information to be serve when requested + // when the transaction is confirmed, store the information to be served when requested dataAccessResponse.on('confirmed', async (dataAccessConfirmedResponse) => { await this.confirmedTransactionStore.addConfirmedTransaction( transactionHash.value, diff --git a/packages/thegraph-data-access/src/data-access.ts b/packages/thegraph-data-access/src/data-access.ts index 7c2faf393a..19bf9333ad 100644 --- a/packages/thegraph-data-access/src/data-access.ts +++ b/packages/thegraph-data-access/src/data-access.ts @@ -4,12 +4,11 @@ import TypedEmitter from 'typed-emitter'; import { BigNumber } from 'ethers'; import { getCurrentTimestampInSecond, retry, SimpleLogger } from '@requestnetwork/utils'; -import { Block } from '@requestnetwork/data-access'; +import { Block, CombinedDataAccess } from '@requestnetwork/data-access'; import { DataAccessTypes, LogTypes, StorageTypes } from '@requestnetwork/types'; import { Transaction } from './queries'; import { SubgraphClient } from './subgraph-client'; -import { CombinedDataAccess } from '@requestnetwork/data-access'; import { PendingStore } from './pending-store'; import { RequestInit } from 'graphql-request/dist/types.dom'; @@ -270,6 +269,7 @@ export class TheGraphDataWrite implements DataAccessTypes.IDataWrite { }; storageResult.on('confirmed', () => { + this.logger.debug(`Looking for ${storageResult.id} in subgraph`); retry( async () => { const response = await this.graphql.getTransactionsByHash(storageResult.id); diff --git a/packages/utils/src/retry.ts b/packages/utils/src/retry.ts index 141cacdb92..3521defa82 100644 --- a/packages/utils/src/retry.ts +++ b/packages/utils/src/retry.ts @@ -37,7 +37,7 @@ const retry = ( maxExponentialBackoffDelay?: number; } = {}, ): ((...params: TParams) => Promise) => { - // If a context was passed in, bind it to to the target function + // If a context was passed in, bind it to the target function if (context) { target = target.bind(context); } From 36915f18608e89bad1018b23873c226cf9515154 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Thu, 11 May 2023 21:43:48 +0200 Subject: [PATCH 3/6] simplify code --- packages/integration-test/test/node-client.test.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/integration-test/test/node-client.test.ts b/packages/integration-test/test/node-client.test.ts index 7049f13058..2395f7a003 100644 --- a/packages/integration-test/test/node-client.test.ts +++ b/packages/integration-test/test/node-client.test.ts @@ -73,12 +73,7 @@ const wrongDecryptionProvider = new EthereumPrivateKeyDecryptionProvider({ const waitForConfirmation = async (input: Request | Types.IRequestDataWithEvents) => { // create the promise to wait for confirmation - let waitForConfirmationPromise: Promise; - if ('waitForConfirmation' in input) { - waitForConfirmationPromise = input.waitForConfirmation(); - } else { - waitForConfirmationPromise = new Promise((resolve) => input.on('confirmed', resolve)); - } + const waitForConfirmationPromise = new Promise((resolve) => input.on('confirmed', resolve)); // in parallel, mine an empty block, because a confirmation needs to wait for two blocks // (the block that persisted the action + another block) From a3c5462dcbbff64adfd11101ed356e84f32b4609 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Thu, 11 May 2023 21:45:13 +0200 Subject: [PATCH 4/6] simplify code --- packages/integration-test/test/node-client.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/integration-test/test/node-client.test.ts b/packages/integration-test/test/node-client.test.ts index 2395f7a003..764a810d2f 100644 --- a/packages/integration-test/test/node-client.test.ts +++ b/packages/integration-test/test/node-client.test.ts @@ -73,7 +73,9 @@ const wrongDecryptionProvider = new EthereumPrivateKeyDecryptionProvider({ const waitForConfirmation = async (input: Request | Types.IRequestDataWithEvents) => { // create the promise to wait for confirmation - const waitForConfirmationPromise = new Promise((resolve) => input.on('confirmed', resolve)); + const waitForConfirmationPromise = new Promise((resolve) => + input.on('confirmed', resolve), + ); // in parallel, mine an empty block, because a confirmation needs to wait for two blocks // (the block that persisted the action + another block) From 2e15ba07b39f2f4e6df9ab8bcc3a515951a92259 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Thu, 11 May 2023 21:46:58 +0200 Subject: [PATCH 5/6] better comments --- packages/integration-test/test/node-client.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/integration-test/test/node-client.test.ts b/packages/integration-test/test/node-client.test.ts index 764a810d2f..73e4cdfa48 100644 --- a/packages/integration-test/test/node-client.test.ts +++ b/packages/integration-test/test/node-client.test.ts @@ -72,22 +72,23 @@ const wrongDecryptionProvider = new EthereumPrivateKeyDecryptionProvider({ }); const waitForConfirmation = async (input: Request | Types.IRequestDataWithEvents) => { - // create the promise to wait for confirmation + // Create the promise to wait for confirmation. const waitForConfirmationPromise = new Promise((resolve) => input.on('confirmed', resolve), ); - // in parallel, mine an empty block, because a confirmation needs to wait for two blocks - // (the block that persisted the action + another block) + // In parallel, mine an empty block, because a confirmation needs to wait for two blocks + // (the block that persisted the action + another block). const mineBlockPromise = provider.send('evm_mine', []); - // set a time limit to wait for confirmation before throwing + // Set a time limit to wait for confirmation before throwing. + // Create the error object right away to conserve context stacktrace. const timeoutError = new Error('waiting for confirmation took too long'); const timeout = setTimeout(() => { throw timeoutError; }, 5000); - // return the confirmation result + // Return the confirmation result. const promiseResults = await Promise.all([waitForConfirmationPromise, mineBlockPromise]); clearTimeout(timeout); return promiseResults[0]; @@ -99,7 +100,6 @@ describe('Request client using a request node', () => { const request = await requestNetwork.createRequest({ requestInfo: requestCreationHashBTC, signer: payeeIdentity, - disableEvents: false, }); expect(request).toBeInstanceOf(Request); expect(request.requestId).toBeDefined(); From cf86847c7644879b96736443d4cae17ecea5b9fe Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Thu, 11 May 2023 21:47:40 +0200 Subject: [PATCH 6/6] better comments --- packages/integration-test/test/node-client.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration-test/test/node-client.test.ts b/packages/integration-test/test/node-client.test.ts index 73e4cdfa48..a4a6fc286a 100644 --- a/packages/integration-test/test/node-client.test.ts +++ b/packages/integration-test/test/node-client.test.ts @@ -82,7 +82,7 @@ const waitForConfirmation = async (input: Request | Types.IRequestDataWithEvents const mineBlockPromise = provider.send('evm_mine', []); // Set a time limit to wait for confirmation before throwing. - // Create the error object right away to conserve context stacktrace. + // Create the error object right away to conserve the context's stacktrace. const timeoutError = new Error('waiting for confirmation took too long'); const timeout = setTimeout(() => { throw timeoutError;