Skip to content

Commit 805bd7e

Browse files
committed
chore: resolve comments
Signed-off-by: nikolay <n.atanasow94@gmail.com>
1 parent ae42e85 commit 805bd7e

File tree

7 files changed

+88
-45
lines changed

7 files changed

+88
-45
lines changed

packages/relay/src/lib/debug.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import { MirrorNodeClient } from './clients';
99
import { IOpcode } from './clients/models/IOpcode';
1010
import { IOpcodesResponse } from './clients/models/IOpcodesResponse';
1111
import constants, { CallType, TracerType } from './constants';
12-
import { rpcMethod, rpcParamValidationRules } from './decorators';
12+
import { cache, rpcMethod, rpcParamValidationRules } from './decorators';
1313
import { predefined } from './errors/JsonRpcError';
1414
import { CommonService } from './services';
15-
import { CacheService } from './services/cacheService/cacheService';
15+
import { CACHE_LEVEL, CacheService } from './services/cacheService/cacheService';
1616
import { ICallTracerConfig, IOpcodeLoggerConfig, ITracerConfig, ParamType, RequestDetails } from './types';
1717

1818
/**
@@ -90,6 +90,7 @@ export class DebugImpl implements Debug {
9090
1: { type: ParamType.COMBINED_TRACER_TYPE, required: false },
9191
2: { type: ParamType.TRACER_CONFIG, required: false },
9292
})
93+
@cache(CacheService.getInstance(CACHE_LEVEL.L1))
9394
async traceTransaction(
9495
transactionIdOrHash: string,
9596
tracer: TracerType,

packages/relay/src/lib/decorators/cache.decorator.ts

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,20 @@ interface CacheOptions {
2626
}
2727

2828
/**
29-
* Skip single params in the following format
29+
* Iterates through the provided 'params' array and checks if any argument in 'args' at the specified 'index'
30+
* matches one of the pipe-separated values in 'value'. If a match is found, caching should be skipped.
3031
*
31-
* [{
32-
* index: '0',
33-
* value: 'pending|safe'
34-
* }]
32+
* @param args - The IArguments arguments object
33+
* @param params - An array of CacheSingleParam caching rules
34+
* @returns 'true' if any argument matches a rule and caching should be skipped; otherwise, 'false'.
3535
*
36-
* @param args
37-
* @param params
36+
* @example
37+
* [{
38+
* index: '0',
39+
* value: 'pending|safe'
40+
* }]
3841
*/
39-
const shouldSkipCachingForSingleParams = (args: any, params: any = []) => {
42+
const shouldSkipCachingForSingleParams = (args: IArguments, params: CacheSingleParam[] = []): boolean => {
4043
for (const item of params) {
4144
const values = item.value.split('|');
4245
if (values.indexOf(args[item.index]) > -1) {
@@ -48,23 +51,29 @@ const shouldSkipCachingForSingleParams = (args: any, params: any = []) => {
4851
};
4952

5053
/**
51-
* Skip named params in the following format
54+
* Determines whether caching should be skipped based on field-level conditions within specific argument objects. For each
55+
* item in 'params', the function inspects a corresponding argument at the specified 'index' in 'args'. It builds
56+
* a list of field-based skip conditions and checks if any of the fields in the input argument match any of the provided
57+
* values (supports multiple values via pipe '|' separators).
5258
*
53-
* [{
54-
* index: '0',
55-
* fields: [{
56-
* name: 'fromBlock', value: 'pending|safe'
57-
* }, {
58-
* name: 'toBlock', value: 'safe|finalized'
59-
* }],
60-
* }]
59+
* @param args - The function's arguments object (e.g., `IArguments`), where values are accessed by index.
60+
* @param params - An array of `CacheNamedParams` defining which arguments and which fields to inspect.
61+
* @returns `true` if any field value matches a skip condition; otherwise, `false`.
6162
*
62-
* @param args
63-
* @param params
63+
* @example
64+
* [{
65+
* index: '0',
66+
* fields: [{
67+
* name: 'fromBlock', value: 'pending|safe'
68+
* }, {
69+
* name: 'toBlock', value: 'safe|finalized'
70+
* }],
71+
* }]
6472
*/
65-
const shouldSkipCachingForNamedParams = (args: any, params: any = []) => {
73+
const shouldSkipCachingForNamedParams = (args: IArguments, params: CacheNamedParams[] = []): boolean => {
6674
for (const item of params) {
6775
const input = args[item.index];
76+
// @ts-ignore
6877
const skipList = Object.assign({}, ...params.filter(el => el.index == item.index)[0].fields.map(el => {
6978
return { [el.name]: el.value };
7079
}));
@@ -81,12 +90,21 @@ const shouldSkipCachingForNamedParams = (args: any, params: any = []) => {
8190
};
8291

8392
/**
84-
* Generate cache key by method name and passed arguments
93+
* Generates a unique cache key string based on the method name and argument values. It serializes each argument (excluding
94+
* instances of `RequestDetails`) into a string format and appends them to the method name to form the final key.
8595
*
86-
* @param methodName
87-
* @param args
96+
* - If an argument is an object, each of its key-value pairs is added to the key.
97+
* - Primitive values are directly appended to the key.
98+
* - Arguments of type `RequestDetails` are ignored in the key generation.
99+
*
100+
* @param methodName - The name of the method being cached.
101+
* @param args - The arguments passed to the method (typically from `IArguments`).
102+
* @returns A string that uniquely identifies the method call for caching purposes.
103+
*
104+
* @example
105+
* generateCacheKey('getBlockByNumber', arguments); // should return getBlockByNumber_0x160c_false
88106
*/
89-
const generateCacheKey = (methodName: string, args: any) => {
107+
const generateCacheKey = (methodName: string, args: IArguments) => {
90108
let cacheKey: string = methodName;
91109
for (const [, value] of Object.entries(args)) {
92110
if (value?.constructor?.name != 'RequestDetails') {
@@ -105,24 +123,42 @@ const generateCacheKey = (methodName: string, args: any) => {
105123
};
106124

107125
/**
108-
* Extract the RequestDetails field from the arguments
126+
* This utility is used to scan through the provided arguments (typically from `IArguments`)
127+
* and return the first value that is identified as an instance of `RequestDetails`.
109128
*
110-
* @param args
129+
* If no such instance is found, it returns a new `RequestDetails` object with empty defaults.
130+
*
131+
* @param args - The arguments object from a function (typically `IArguments`).
132+
* @returns The first found `RequestDetails` instance, or a new one with default values if none is found.
111133
*/
112-
const extractRequestDetails = (args: any): RequestDetails => {
113-
let requestId, ipAddress, connectionId: string = '';
134+
const extractRequestDetails = (args: IArguments): RequestDetails => {
114135
for (const [, value] of Object.entries(args)) {
115136
if (value?.constructor?.name == 'RequestDetails') {
116-
requestId = value['requestId'];
117-
ipAddress = value['ipAddress'];
118-
connectionId = value['connectionId'];
119-
break;
137+
// @ts-ignore
138+
return value;
120139
}
121140
}
122141

123-
return new RequestDetails({ requestId, ipAddress, connectionId });
142+
return new RequestDetails({ requestId: '', ipAddress: '' });
124143
};
125144

145+
/**
146+
* This decorator uses a `CacheService` to attempt to retrieve a cached result before executing the original method. If
147+
* no cached response exists, the method is executed and its result may be stored in the cache depending on configurable
148+
* options. Caching can be conditionally skipped based on runtime arguments via `skipParams` (for positional args)
149+
* and `skipNamedParams` (for object args).
150+
*
151+
* @param cacheService - The caching service used to store and retrieve cache entries.
152+
* @param options - Optional configuration for caching behavior.
153+
* @property skipParams - An array of rules for skipping caching based on specific argument values.
154+
* @property skipNamedParams - An array of rules for skipping caching based on fields within argument objects.
155+
* @property ttl - Optional time-to-live for the cache entry; falls back to global config if not provided.
156+
*
157+
* @returns A method decorator function that wraps the original method with caching logic.
158+
*
159+
* @example
160+
* @cache(CacheService, { skipParams: [...], skipNamesParams: [...], ttl: 300 })
161+
*/
126162
export function cache(cacheService: CacheService, options: CacheOptions = {}) {
127163
return function(_target: any, _propertyKey: string, descriptor: PropertyDescriptor) {
128164
const method = descriptor.value;

packages/relay/src/lib/eth.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
IBlockService,
2020
ICommonService,
2121
IContractService,
22-
TransactionService,
22+
TransactionService
2323
} from './services';
2424
import { CACHE_LEVEL, CacheService } from './services/cacheService/cacheService';
2525
import { FeeService } from './services/ethService/feeService/FeeService';
@@ -174,7 +174,7 @@ export class EthImpl implements Eth {
174174
})
175175
@rpcParamLayoutConfig(RPC_LAYOUT.custom((params) => [Number(params[0]), params[1], params[2]]))
176176
@cache(CacheService.getInstance(CACHE_LEVEL.L1), {
177-
skipParams: [{ index: '2', value: constants.NON_CACHABLE_BLOCK_PARAMS }],
177+
skipParams: [{ index: '1', value: constants.NON_CACHABLE_BLOCK_PARAMS }],
178178
ttl: constants.CACHE_TTL.FIFTEEN_MINUTES,
179179
})
180180
async feeHistory(
@@ -678,6 +678,9 @@ export class EthImpl implements Eth {
678678
2: { type: ParamType.BLOCK_NUMBER_OR_HASH, required: false },
679679
})
680680
@rpcParamLayoutConfig(RPC_LAYOUT.custom((params) => [params[0], params[1], params[2]]))
681+
@cache(CacheService.getInstance(CACHE_LEVEL.L1), {
682+
skipParams: [{ index: '2', value: constants.NON_CACHABLE_BLOCK_PARAMS }],
683+
})
681684
async getStorageAt(
682685
address: string,
683686
slot: string,
@@ -909,6 +912,9 @@ export class EthImpl implements Eth {
909912
0: { type: ParamType.ADDRESS, required: true },
910913
1: { type: ParamType.BLOCK_NUMBER_OR_HASH, required: true },
911914
})
915+
@cache(CacheService.getInstance(CACHE_LEVEL.L1), {
916+
skipParams: [{ index: '1', value: constants.NON_CACHABLE_BLOCK_PARAMS }],
917+
})
912918
async getTransactionCount(
913919
address: string,
914920
blockNumOrTag: string | null,
@@ -951,6 +957,9 @@ export class EthImpl implements Eth {
951957
0: { type: ParamType.TRANSACTION, required: true },
952958
1: { type: ParamType.BLOCK_PARAMS, required: true },
953959
})
960+
@cache(CacheService.getInstance(CACHE_LEVEL.L1), {
961+
skipParams: [{ index: '1', value: constants.NON_CACHABLE_BLOCK_PARAMS }],
962+
})
954963
public async call(
955964
call: IContractCallRequest,
956965
blockParam: string | object | null,

packages/relay/src/lib/services/cacheService/cacheService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class CacheService {
123123
*/
124124
public static getInstance(type: CACHE_LEVEL, registry: Registry = new Registry(), reservedKeys: Set<string> = new Set()): CacheService {
125125
if (!this.instances[type]) {
126-
const logger = pino({ level: 'silent' });
126+
const logger = pino({ level: ConfigService.get('LOG_LEVEL') });
127127
this.instances[type] = new CacheService(logger.child({ name: type }), registry, reservedKeys);
128128
}
129129

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { EvmAddressHbarSpendingPlanRepository } from '../../../src/lib/db/reposi
1313
import { HbarSpendingPlanRepository } from '../../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository';
1414
import { IPAddressHbarSpendingPlanRepository } from '../../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository';
1515
import { EthImpl } from '../../../src/lib/eth';
16-
import { ContractService } from '../../../src/lib/services';
1716
import { CommonService } from '../../../src/lib/services';
1817
import { CACHE_LEVEL, CacheService } from '../../../src/lib/services/cacheService/cacheService';
1918
import HAPIService from '../../../src/lib/services/hapiService/hapiService';

packages/relay/tests/lib/eth/eth_feeHistory.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ describe('@ethFeeHistory using MirrorNode', async function () {
298298

299299
const countBlocks = 2;
300300

301-
const feeHistory = await ethImpl.feeHistory(countBlocks, 'latest', [], requestDetails);
301+
const feeHistory = await ethImpl.feeHistory(countBlocks, numberTo0x(latestBlockNumber), [], requestDetails);
302302

303303
checkCommonFeeHistoryFields(feeHistory);
304304
expect(feeHistory['oldestBlock']).to.eq(numberTo0x(latestBlockNumber - countBlocks + 1));
@@ -307,7 +307,7 @@ describe('@ethFeeHistory using MirrorNode', async function () {
307307
restMock.onGet(BLOCKS_LIMIT_ORDER_URL).reply(404, JSON.stringify({}));
308308
restMock.onGet(`blocks/${latestBlock.number}`).reply(404, JSON.stringify({}));
309309

310-
const feeHistoryUsingCache = await ethImpl.feeHistory(countBlocks, 'latest', [], requestDetails);
310+
const feeHistoryUsingCache = await ethImpl.feeHistory(countBlocks, numberTo0x(latestBlockNumber), [], requestDetails);
311311
checkCommonFeeHistoryFields(feeHistoryUsingCache);
312312
expect(feeHistoryUsingCache['oldestBlock']).to.eq(numberTo0x(latestBlockNumber - countBlocks + 1));
313313
expect(feeHistoryUsingCache['baseFeePerGas'].length).to.eq(countBlocks + 1);

packages/relay/tests/lib/eth/eth_getBlockReceipts.spec.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import sinon from 'sinon';
88
import { numberTo0x } from '../../../dist/formatters';
99
import { SDKClient } from '../../../src/lib/clients';
1010
import { EthImpl } from '../../../src/lib/eth';
11-
import { ContractService } from '../../../src/lib/services';
1211
import { CacheService } from '../../../src/lib/services/cacheService/cacheService';
1312
import HAPIService from '../../../src/lib/services/hapiService/hapiService';
1413
import { RequestDetails } from '../../../src/lib/types';
@@ -53,9 +52,8 @@ describe('@ethGetBlockReceipts using MirrorNode', async function () {
5352
this.beforeEach(async () => {
5453
// reset cache and restMock
5554
await cacheService.clear(requestDetails);
56-
currentGasPriceStub = sinon.stub(ethImpl.common, 'getCurrentGasPriceForBlock').resolves('0x25');
57-
extractBlockNumberOrTagStub = sinon
58-
.stub(ethImpl.contractService, 'extractBlockNumberOrTag')
55+
currentGasPriceStub = sinon.stub(ethImpl['common'], 'getCurrentGasPriceForBlock').resolves('0x25');
56+
extractBlockNumberOrTagStub = sinon.stub(ethImpl['contractService'], 'extractBlockNumberOrTag')
5957
.resolves(BLOCK_NUMBER.toString());
6058
sdkClientStub = sinon.createStubInstance(SDKClient);
6159
getSdkClientStub = sinon.stub(hapiServiceInstance, 'getSDKClient').returns(sdkClientStub);

0 commit comments

Comments
 (0)