-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Logan Nguyen <[email protected]>
- Loading branch information
1 parent
b0617e5
commit d4302bd
Showing
1 changed file
with
45 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<SDKClient>; | ||
let mirrorNodeStub: sinon.SinonStubbedInstance<MirrorNodeClient>; | ||
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 = '[email protected]'; | ||
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); | ||
}); | ||
}); | ||
}); | ||
}); |