From d4302bdb07e086c319442a1c0775a9559aa03065 Mon Sep 17 00:00:00 2001 From: Logan Nguyen Date: Wed, 6 Nov 2024 14:44:03 -0600 Subject: [PATCH] test: fixed unit tests Signed-off-by: Logan Nguyen --- .../lib/eth/eth_sendRawTransaction.spec.ts | 101 ++++++++---------- 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts index 75454e15a..c54dcbf34 100644 --- a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts +++ b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts @@ -20,6 +20,7 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { expect, use } from 'chai'; +import createHash from 'keccak'; import sinon from 'sinon'; import chaiAsPromised from 'chai-as-promised'; import { @@ -51,9 +52,7 @@ import * as utils from '../../../src/formatters'; use(chaiAsPromised); let sdkClientStub: sinon.SinonStubbedInstance; -let mirrorNodeStub: sinon.SinonStubbedInstance; let getSdkClientStub: sinon.SinonStub; -let formatTransactionIdWithoutQueryParamsStub: sinon.SinonStub; describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () { this.timeout(10000); @@ -74,7 +73,6 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () await cacheService.clear(requestDetails); restMock.reset(); sdkClientStub = sinon.createStubInstance(SDKClient); - mirrorNodeStub = sinon.createStubInstance(MirrorNodeClient); getSdkClientStub = sinon.stub(hapiServiceInstance, 'getSDKClient').returns(sdkClientStub); restMock.onGet('network/fees').reply(200, DEFAULT_NETWORK_FEES); }); @@ -91,7 +89,7 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () const transactionIdServicesFormat = '0.0.902@1684375868.230217103'; const transactionId = '0.0.902-1684375868-230217103'; const value = '0x511617DE831B9E173'; - const contractResultEndpoint = `contracts/results/${transactionId}`; + const getTransactionByIdEndpoint = `transactions/${transactionId}?nonce=0`; const networkExchangeRateEndpoint = 'network/exchangerate'; const ethereumHash = '0x6d20b034eecc8d455c4c040fb3763082d499353a8b7d318b1085ad8d7de15f7e'; const mockedExchangeRate = { @@ -160,17 +158,20 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () sdkClientStub.logger = pino(); sdkClientStub.deleteFile.resolves(); - restMock.onGet(contractResultEndpoint).reply(200, { hash: ethereumHash }); + restMock.onGet(getTransactionByIdEndpoint).reply(200, {}); const signed = await signTransaction({ ...transaction, data: '0x' + '22'.repeat(13000), }); + const txBuffer = Buffer.from(signed.replace('0x', ''), 'hex'); + const expectedHash = utils.prepend0x(createHash('keccak256').update(txBuffer).digest('hex')); const resultingHash = await ethImpl.sendRawTransaction(signed, requestDetails); + expect(eventEmitterMock.emit.callCount).to.equal(1); expect(hbarLimiterMock.shouldLimit.callCount).to.equal(1); - expect(resultingHash).to.equal(ethereumHash); + expect(resultingHash).to.equal(expectedHash); }); it('should return a predefined GAS_LIMIT_TOO_HIGH instead of NUMERIC_FAULT as precheck exception', async function () { @@ -189,7 +190,7 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () it('should return a computed hash if unable to retrieve EthereumHash from record due to contract revert', async function () { const signed = await signTransaction(transaction); - restMock.onGet(`transactions/${transactionId}`).reply(200, null); + restMock.onGet(getTransactionByIdEndpoint).reply(200, null); const resultingHash = await ethImpl.sendRawTransaction(signed, requestDetails); expect(resultingHash).to.equal(ethereumHash); @@ -198,12 +199,11 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () it('should throw internal error when transaction returned from mirror node is null', async function () { const signed = await signTransaction(transaction); - restMock.onGet(contractResultEndpoint).reply(404, mockData.notFound); - restMock.onGet(`transactions/${transactionId}?nonce=0`).reply(200, null); + restMock.onGet(getTransactionByIdEndpoint).reply(200, null); sdkClientStub.submitEthereumTransaction.resolves({ txResponse: { - transactionId: '', + transactionId: transactionIdServicesFormat, } as unknown as TransactionResponse, fileId: null, }); @@ -217,7 +217,7 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () it('should throw internal error when transactionID is invalid', async function () { const signed = await signTransaction(transaction); - restMock.onGet(contractResultEndpoint).reply(200, { hash: ethereumHash }); + restMock.onGet(getTransactionByIdEndpoint).reply(200, {}); sdkClientStub.submitEthereumTransaction.resolves({ txResponse: { @@ -232,8 +232,8 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () expect(`Error invoking RPC: ${response.message}`).to.equal(predefined.INTERNAL_ERROR(response.message).message); }); - it('should return hash from ContractResult mirror node api', async function () { - restMock.onGet(contractResultEndpoint).reply(200, { hash: ethereumHash }); + it('should return hash by calculating transaction hash using keccak256', async function () { + restMock.onGet(getTransactionByIdEndpoint).reply(200, {}); sdkClientStub.submitEthereumTransaction.resolves({ txResponse: { @@ -242,13 +242,15 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () fileId: null, }); const signed = await signTransaction(transaction); + const txBuffer = Buffer.from(signed.replace('0x', ''), 'hex'); + const expectedHash = utils.prepend0x(createHash('keccak256').update(txBuffer).digest('hex')); const resultingHash = await ethImpl.sendRawTransaction(signed, requestDetails); - expect(resultingHash).to.equal(ethereumHash); + expect(resultingHash).to.equal(expectedHash); }); it('should not send second transaction upon succession', async function () { - restMock.onGet(contractResultEndpoint).reply(200, { hash: ethereumHash }); + restMock.onGet(getTransactionByIdEndpoint).reply(200, {}); sdkClientStub.submitEthereumTransaction.resolves({ txResponse: { @@ -295,54 +297,41 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () ); }); - it('should call mirror node upon time out and return successful if found', async function () { - const transactionId = '0.0.902'; - const contractResultEndpoint = `contracts/results/${transactionId}`; - formatTransactionIdWithoutQueryParamsStub = sinon.stub(utils, 'formatTransactionIdWithoutQueryParams'); - formatTransactionIdWithoutQueryParamsStub.returns(transactionId); - - restMock.onGet(contractResultEndpoint).reply(200, { hash: ethereumHash }); + ['timeout exceeded', 'Connection dropped'].forEach((error) => { + it(`should poll mirror node upon ${error} error for valid transaction and return correct transaction hash`, async function () { + restMock + .onGet(getTransactionByIdEndpoint) + .replyOnce(404, mockData.notFound) + .onGet(getTransactionByIdEndpoint) + .reply(200, {}); - sdkClientStub.submitEthereumTransaction.restore(); - mirrorNodeStub.repeatedRequest = sinon.stub(); - mirrorNodeStub.getTransactionById = sinon.stub(); - sdkClientStub.deleteFile.resolves(); - sdkClientStub.createFile.resolves(new FileId(0, 0, 5644)); - sdkClientStub.executeTransaction - .onCall(0) - .throws(new SDKClientError({ status: 21 }, 'timeout exceeded', transactionId)); - const signed = await signTransaction(transaction); - - const resultingHash = await ethImpl.sendRawTransaction(signed, requestDetails); - expect(resultingHash).to.equal(ethereumHash); - }); + sdkClientStub.submitEthereumTransaction + .onCall(0) + .throws(new SDKClientError({ status: 21 }, error, transactionIdServicesFormat)); - it('should call mirror node upon time out and throw error if not found', async function () { - sdkClientStub.submitEthereumTransaction.restore(); - mirrorNodeStub.repeatedRequest = sinon.stub(); - mirrorNodeStub.getTransactionById = sinon.stub(); + const signed = await signTransaction(transaction); - sdkClientStub.createFile.resolves(new FileId(0, 0, 5644)); - sdkClientStub.executeTransaction.onCall(0).throws(new SDKClientError({ status: 21 }, 'timeout exceeded')); - const signed = await signTransaction(transaction); + const resultingHash = await ethImpl.sendRawTransaction(signed, requestDetails); + expect(resultingHash).to.equal(ethereumHash); + }); - const response = (await ethImpl.sendRawTransaction(signed, requestDetails)) as JsonRpcError; - expect(response).to.be.instanceOf(JsonRpcError); - expect(response.message).to.include('timeout exceeded'); - }); + it(`should poll mirror node upon ${error} error for valid transaction and return correct ${error} error if no transaction is found`, async function () { + restMock + .onGet(getTransactionByIdEndpoint) + .replyOnce(404, mockData.notFound) + .onGet(getTransactionByIdEndpoint) + .reply(200, null); - it('should call mirror node upon connection dropped and throw error if not found', async function () { - sdkClientStub.submitEthereumTransaction.restore(); - mirrorNodeStub.repeatedRequest = sinon.stub(); - mirrorNodeStub.getTransactionById = sinon.stub(); + sdkClientStub.submitEthereumTransaction + .onCall(0) + .throws(new SDKClientError({ status: 21 }, error, transactionIdServicesFormat)); - sdkClientStub.createFile.resolves(new FileId(0, 0, 5644)); - sdkClientStub.executeTransaction.onCall(0).throws(new SDKClientError({ status: 21 }, 'Connection dropped')); - const signed = await signTransaction(transaction); + const signed = await signTransaction(transaction); - const response = (await ethImpl.sendRawTransaction(signed, requestDetails)) as JsonRpcError; - expect(response).to.be.instanceOf(JsonRpcError); - expect(response.message).to.include('Connection dropped'); + const response = (await ethImpl.sendRawTransaction(signed, requestDetails)) as JsonRpcError; + expect(response).to.be.instanceOf(JsonRpcError); + expect(response.message).to.include(error); + }); }); }); });