Skip to content

Commit 03fee22

Browse files
fix: unit tests failing in CI (#2258)
* Fixes tests that were not being executed due to error Signed-off-by: Konstantina Blazhukova <[email protected]> * Fixes formatting Signed-off-by: Konstantina Blazhukova <[email protected]> * Refactors default transaction Signed-off-by: Konstantina Blazhukova <[email protected]> * Refactors precheck; adds JSDoc; removes unecessary let etc. Signed-off-by: Konstantina Blazhukova <[email protected]> * Removes console.log Signed-off-by: Konstantina Blazhukova <[email protected]> * Addresses PR comments Signed-off-by: Konstantina Blazhukova <[email protected]> * Improves variable check Signed-off-by: Konstantina Blazhukova <[email protected]> * Removes unecessary cosmetic change Signed-off-by: Konstantina Blazhukova <[email protected]> --------- Signed-off-by: Konstantina Blazhukova <[email protected]>
1 parent 40f72bc commit 03fee22

File tree

3 files changed

+114
-58
lines changed

3 files changed

+114
-58
lines changed

packages/relay/src/lib/precheck.ts

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,43 +26,69 @@ import constants from './constants';
2626
import { ethers, Transaction } from 'ethers';
2727
import { formatRequestIdMessage, prepend0x } from '../formatters';
2828

29+
/**
30+
* Precheck class for handling various prechecks before sending a raw transaction.
31+
*/
2932
export class Precheck {
30-
private mirrorNodeClient: MirrorNodeClient;
33+
private readonly mirrorNodeClient: MirrorNodeClient;
3134
private readonly chain: string;
3235
private readonly logger: Logger;
3336

37+
/**
38+
* Creates an instance of Precheck.
39+
* @param {MirrorNodeClient} mirrorNodeClient - The MirrorNodeClient instance.
40+
* @param {Logger} logger - The logger instance.
41+
* @param {string} chainId - The chain ID.
42+
*/
3443
constructor(mirrorNodeClient: MirrorNodeClient, logger: Logger, chainId: string) {
3544
this.mirrorNodeClient = mirrorNodeClient;
3645
this.logger = logger;
3746
this.chain = chainId;
3847
}
3948

49+
/**
50+
* Parses the transaction if needed.
51+
* @param {string | Transaction} transaction - The transaction to parse.
52+
* @returns {Transaction} The parsed transaction.
53+
*/
4054
public static parseTxIfNeeded(transaction: string | Transaction): Transaction {
4155
return typeof transaction === 'string' ? Transaction.from(transaction) : transaction;
4256
}
4357

44-
value(tx: Transaction) {
58+
/**
59+
* Checks if the value of the transaction is valid.
60+
* @param {Transaction} tx - The transaction.
61+
*/
62+
value(tx: Transaction): void {
4563
if (tx.data === EthImpl.emptyHex && tx.value < constants.TINYBAR_TO_WEIBAR_COEF) {
4664
throw predefined.VALUE_TOO_LOW;
4765
}
4866
}
4967

5068
/**
51-
* @param transaction
52-
* @param gasPrice
69+
* Sends a raw transaction after performing various prechecks.
70+
* @param {ethers.Transaction} parsedTx - The parsed transaction.
71+
* @param {number} gasPrice - The gas price.
72+
* @param {string} [requestId] - The request ID.
5373
*/
54-
async sendRawTransactionCheck(parsedTx: ethers.Transaction, gasPrice: number, requestId?: string) {
74+
async sendRawTransactionCheck(parsedTx: ethers.Transaction, gasPrice: number, requestId?: string): Promise<void> {
5575
this.transactionType(parsedTx, requestId);
5676
this.gasLimit(parsedTx, requestId);
5777
const mirrorAccountInfo = await this.verifyAccount(parsedTx, requestId);
58-
await this.nonce(parsedTx, mirrorAccountInfo.ethereum_nonce, requestId);
78+
this.nonce(parsedTx, mirrorAccountInfo.ethereum_nonce, requestId);
5979
this.chainId(parsedTx, requestId);
6080
this.value(parsedTx);
6181
this.gasPrice(parsedTx, gasPrice, requestId);
62-
await this.balance(parsedTx, mirrorAccountInfo, requestId);
82+
this.balance(parsedTx, mirrorAccountInfo, requestId);
6383
}
6484

65-
async verifyAccount(tx: Transaction, requestId?: string) {
85+
/**
86+
* Verifies the account.
87+
* @param {Transaction} tx - The transaction.
88+
* @param {string} [requestId] - The request ID.
89+
* @returns {Promise<any>} A Promise.
90+
*/
91+
async verifyAccount(tx: Transaction, requestId?: string): Promise<any> {
6692
const requestIdPrefix = formatRequestIdMessage(requestId);
6793
// verify account
6894
const accountInfo = await this.mirrorNodeClient.getAccount(tx.from!, requestId);
@@ -81,9 +107,12 @@ export class Precheck {
81107
}
82108

83109
/**
84-
* @param tx
110+
* Checks the nonce of the transaction.
111+
* @param {Transaction} tx - The transaction.
112+
* @param {number} accountInfoNonce - The nonce of the account.
113+
* @param {string} [requestId] - The request ID.
85114
*/
86-
async nonce(tx: Transaction, accountInfoNonce: number, requestId?: string) {
115+
nonce(tx: Transaction, accountInfoNonce: number, requestId?: string): void {
87116
const requestIdPrefix = formatRequestIdMessage(requestId);
88117
this.logger.trace(
89118
`${requestIdPrefix} Nonce precheck for sendRawTransaction(tx.nonce=${tx.nonce}, accountInfoNonce=${accountInfoNonce})`,
@@ -96,9 +125,11 @@ export class Precheck {
96125
}
97126

98127
/**
99-
* @param tx
128+
* Checks the chain ID of the transaction.
129+
* @param {Transaction} tx - The transaction.
130+
* @param {string} [requestId] - The request ID.
100131
*/
101-
chainId(tx: Transaction, requestId?: string) {
132+
chainId(tx: Transaction, requestId?: string): void {
102133
const requestIdPrefix = formatRequestIdMessage(requestId);
103134
const txChainId = prepend0x(Number(tx.chainId).toString(16));
104135
const passes = this.isLegacyUnprotectedEtx(tx) || txChainId === this.chain;
@@ -124,10 +155,12 @@ export class Precheck {
124155
}
125156

126157
/**
127-
* @param tx
128-
* @param gasPrice
158+
* Checks the gas price of the transaction.
159+
* @param {Transaction} tx - The transaction.
160+
* @param {number} gasPrice - The gas price.
161+
* @param {string} [requestId] - The request ID.
129162
*/
130-
gasPrice(tx: Transaction, gasPrice: number, requestId?: string) {
163+
gasPrice(tx: Transaction, gasPrice: number, requestId?: string): void {
131164
const requestIdPrefix = formatRequestIdMessage(requestId);
132165
const minGasPrice = BigInt(gasPrice);
133166
const txGasPrice = tx.gasPrice || tx.maxFeePerGas! + tx.maxPriorityFeePerGas!;
@@ -169,10 +202,12 @@ export class Precheck {
169202
}
170203

171204
/**
172-
* @param tx
173-
* @param callerName
205+
* Checks the balance of the sender account.
206+
* @param {Transaction} tx - The transaction.
207+
* @param {any} account - The account information.
208+
* @param {string} [requestId] - The request ID.
174209
*/
175-
async balance(tx: Transaction, account: any, requestId?: string) {
210+
balance(tx: Transaction, account: any, requestId?: string): void {
176211
const requestIdPrefix = formatRequestIdMessage(requestId);
177212
const result = {
178213
passes: false,
@@ -221,9 +256,11 @@ export class Precheck {
221256
}
222257

223258
/**
224-
* @param tx
259+
* Checks the gas limit of the transaction.
260+
* @param {Transaction} tx - The transaction.
261+
* @param {string} [requestId] - The request ID.
225262
*/
226-
gasLimit(tx: Transaction, requestId?: string) {
263+
gasLimit(tx: Transaction, requestId?: string): void {
227264
const requestIdPrefix = formatRequestIdMessage(requestId);
228265
const gasLimit = Number(tx.gasLimit);
229266
const failBaseLog = 'Failed gasLimit precheck for sendRawTransaction(transaction=%s).';
@@ -253,11 +290,12 @@ export class Precheck {
253290
* Calculates the intrinsic gas cost based on the number of bytes in the data field.
254291
* Using a loop that goes through every two characters in the string it counts the zero and non-zero bytes.
255292
* Every two characters that are packed together and are both zero counts towards zero bytes.
256-
* @param data
293+
* @param {string} data - The data with the bytes to be calculated
294+
* @returns {number} The intrinsic gas cost.
257295
* @private
258296
*/
259-
private static transactionIntrinsicGasCost(data: string) {
260-
let trimmedData = data.replace('0x', '');
297+
private static transactionIntrinsicGasCost(data: string): number {
298+
const trimmedData = data.replace('0x', '');
261299

262300
let zeros = 0;
263301
let nonZeros = 0;
@@ -277,7 +315,8 @@ export class Precheck {
277315

278316
/**
279317
* Converts hex string to bytes array
280-
* @param hex the hex string you want to convert
318+
* @param {string} hex - The hex string you want to convert.
319+
* @returns {Uint8Array} The bytes array.
281320
*/
282321
hexToBytes(hex: string): Uint8Array {
283322
if (hex === '') {
@@ -293,6 +332,10 @@ export class Precheck {
293332
return Uint8Array.from(Buffer.from(hex, 'hex'));
294333
}
295334

335+
/**
336+
* Checks the size of the transaction.
337+
* @param {string} transaction - The transaction to check.
338+
*/
296339
checkSize(transaction: string): void {
297340
const transactionToBytes: Uint8Array = this.hexToBytes(transaction);
298341
const transactionSize: number = transactionToBytes.length;

packages/relay/tests/lib/eth/eth-helpers.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
/*-
2+
*
3+
* Hedera JSON RPC Relay
4+
*
5+
* Copyright (C) 2023 Hedera Hashgraph, LLC
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
121
import { CacheService } from '../../../src/lib/services/cacheService/cacheService';
222
import pino from 'pino';
323
import { Registry } from 'prom-client';

packages/relay/tests/lib/precheck.spec.ts

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*
1919
*/
2020

21-
import { Assertion, expect } from 'chai';
21+
import { expect } from 'chai';
2222
import { Registry } from 'prom-client';
2323
import { Hbar, HbarUnit } from '@hashgraph/sdk';
2424
const registry = new Registry();
@@ -29,13 +29,14 @@ import { blobVersionedHash, contractAddress1, expectedError, mockData, signTrans
2929
import { MirrorNodeClient } from '../../src/lib/clients';
3030
import axios from 'axios';
3131
import MockAdapter from 'axios-mock-adapter';
32-
import { ethers } from 'ethers';
32+
import { Transaction, ethers } from 'ethers';
3333
import constants from '../../src/lib/constants';
3434
import { JsonRpcError, predefined } from '../../src';
3535
import { CacheService } from '../../src/lib/services/cacheService/cacheService';
3636
const logger = pino();
3737

3838
const limitOrderPostFix = '?order=desc&limit=1';
39+
const transactionsPostFix = '?transactions=false';
3940

4041
describe('Precheck', async function () {
4142
const txWithMatchingChainId =
@@ -59,10 +60,18 @@ describe('Precheck', async function () {
5960
const parsedTxWithValueLessThanOneTinybarAndNotEmptyData = ethers.Transaction.from(
6061
txWithValueLessThanOneTinybarAndNotEmptyData,
6162
);
62-
const oneTinyBar = ethers.parseUnits('1', 10);
63+
6364
const defaultGasPrice = 720_000_000_000;
6465
const defaultGasLimit = 1_000_000;
6566
const defaultChainId = Number('0x12a');
67+
const defaultTx = {
68+
gasLimit: defaultGasLimit,
69+
gasPrice: defaultGasPrice,
70+
chainId: defaultChainId,
71+
maxFeePerGas: null,
72+
maxPriorityFeePerGas: null,
73+
};
74+
6675
let precheck: Precheck;
6776
let mock: MockAdapter;
6877

@@ -167,12 +176,6 @@ describe('Precheck', async function () {
167176
});
168177

169178
describe('gasLimit', async function () {
170-
const defaultTx = {
171-
value: oneTinyBar,
172-
gasPrice: defaultGasPrice,
173-
chainId: defaultChainId,
174-
};
175-
176179
function testFailingGasLimitPrecheck(gasLimits, errorCode) {
177180
for (const gasLimit of gasLimits) {
178181
it(`should fail for gasLimit: ${gasLimit}`, async function () {
@@ -393,13 +396,6 @@ describe('Precheck', async function () {
393396

394397
describe('nonce', async function () {
395398
const defaultNonce = 3;
396-
const defaultTx = {
397-
value: oneTinyBar,
398-
gasPrice: defaultGasPrice,
399-
chainId: defaultChainId,
400-
nonce: defaultNonce,
401-
};
402-
403399
const mirrorAccount = {
404400
ethereum_nonce: defaultNonce,
405401
};
@@ -450,25 +446,22 @@ describe('Precheck', async function () {
450446
});
451447

452448
describe('account', async function () {
453-
const defaultNonce = 3;
454-
const defaultTx = {
455-
value: oneTinyBar,
456-
gasPrice: defaultGasPrice,
457-
chainId: defaultChainId,
458-
nonce: defaultNonce,
459-
from: mockData.accountEvmAddress,
460-
};
461-
462-
const signed = await signTransaction(defaultTx);
463-
const parsedTx = ethers.Transaction.from(signed);
449+
let parsedTx: Transaction;
450+
let mirrorAccount: any;
451+
const defaultNonce: number = 3;
464452

465-
const mirrorAccount = {
466-
evm_address: mockData.accountEvmAddress,
467-
ethereum_nonce: defaultNonce,
468-
};
453+
before(async () => {
454+
const wallet = ethers.Wallet.createRandom();
455+
const signed = await wallet.signTransaction({ ...defaultTx, from: wallet.address, nonce: defaultNonce });
456+
parsedTx = ethers.Transaction.from(signed);
457+
mirrorAccount = {
458+
evm_address: parsedTx.from,
459+
ethereum_nonce: defaultNonce,
460+
};
461+
});
469462

470463
it(`should fail for missing account`, async function () {
471-
mock.onGet(`accounts/${mockData.accountEvmAddress}${limitOrderPostFix}`).reply(404, mockData.notFound);
464+
mock.onGet(`accounts/${parsedTx.from}${transactionsPostFix}`).reply(404, mockData.notFound);
472465

473466
try {
474467
await precheck.verifyAccount(parsedTx);
@@ -477,12 +470,12 @@ describe('Precheck', async function () {
477470
expect(e).to.exist;
478471
expect(e.code).to.eq(-32001);
479472
expect(e.name).to.eq('Resource not found');
480-
expect(e.message).to.contain(mockData.accountEvmAddress);
473+
expect(e.message).to.contain(parsedTx.from);
481474
}
482475
});
483476

484477
it(`should not fail for matched account`, async function () {
485-
mock.onGet(`accounts/${mockData.accountEvmAddress}${limitOrderPostFix}`).reply(200, mirrorAccount);
478+
mock.onGet(`accounts/${parsedTx.from}${transactionsPostFix}`).reply(200, mirrorAccount);
486479
const account = await precheck.verifyAccount(parsedTx);
487480

488481
expect(account.ethereum_nonce).to.eq(defaultNonce);

0 commit comments

Comments
 (0)