Skip to content

Commit e7a6eee

Browse files
authored
Cache the account mirror node query on estimateGas and getTransactionByHash (#931)
* Add cache Signed-off-by: nikolay <[email protected]> * Add tests Signed-off-by: nikolay <[email protected]> --------- Signed-off-by: nikolay <[email protected]>
1 parent dac39b0 commit e7a6eee

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

packages/relay/src/lib/eth.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,21 @@ export class EthImpl implements Eth {
332332
this.logger.trace(`${requestIdPrefix} estimateGas(transaction=${JSON.stringify(transaction)}, _blockParam=${_blockParam})`);
333333
//this checks whether this is a transfer transaction and not a contract function execution
334334
if (!transaction || !transaction.data || transaction.data === '0x') {
335-
const toAccount = await this.mirrorNodeClient.getAccount(transaction.to);
335+
const accountCacheKey = `account_${transaction.to}`;
336+
let toAccount: object | null = this.cache.get(accountCacheKey);
337+
if (!toAccount) {
338+
toAccount = await this.mirrorNodeClient.getAccount(transaction.to);
339+
}
340+
336341
// when account exists return default base gas, otherwise return the minimum amount of gas to create an account entity
337-
return toAccount ? EthImpl.gasTxBaseCost : EthImpl.gasTxHollowAccountCreation;
342+
if (toAccount) {
343+
this.logger.trace(`${requestIdPrefix} caching ${accountCacheKey} for ${constants.CACHE_TTL.ONE_HOUR} ms`);
344+
this.cache.set(accountCacheKey, toAccount);
345+
346+
return EthImpl.gasTxBaseCost;
347+
}
348+
349+
return EthImpl.gasTxHollowAccountCreation;
338350
} else {
339351
return EthImpl.defaultGas;
340352
}
@@ -562,7 +574,7 @@ export class EthImpl implements Eth {
562574
if (stateChange) {
563575
result = stateChange.value_written;
564576
}
565-
}
577+
}
566578
})
567579
.catch((error: any) => {
568580
throw this.genericErrorHandler(
@@ -896,7 +908,7 @@ export class EthImpl implements Eth {
896908
try {
897909
const parsedTx = Precheck.parseTxIfNeeded(transaction);
898910
interactingEntity = parsedTx.to ? parsedTx.to.toString() : '';
899-
const gasPrice = await this.getFeeWeibars(EthImpl.ethSendRawTransaction, requestId);
911+
const gasPrice = Number(await this.gasPrice(requestId));
900912
await this.precheck.sendRawTransactionCheck(parsedTx, gasPrice, requestId);
901913
} catch (e: any) {
902914
throw this.genericErrorHandler(e);
@@ -1033,7 +1045,17 @@ export class EthImpl implements Eth {
10331045
let fromAddress;
10341046
if (contractResult.from) {
10351047
fromAddress = contractResult.from.substring(0, 42);
1036-
const accountResult = await this.mirrorNodeClient.getAccount(fromAddress, requestId);
1048+
1049+
const accountCacheKey = `account_${fromAddress}`;
1050+
let accountResult: any | null = this.cache.get(accountCacheKey);
1051+
if (!accountResult) {
1052+
accountResult = await this.mirrorNodeClient.getAccount(fromAddress, requestId);
1053+
if (accountResult) {
1054+
this.logger.trace(`${requestIdPrefix} caching ${accountCacheKey} for ${constants.CACHE_TTL.ONE_HOUR} ms`);
1055+
this.cache.set(accountCacheKey, accountResult);
1056+
}
1057+
}
1058+
10371059
if (accountResult && accountResult.evm_address && accountResult.evm_address.length > 0) {
10381060
fromAddress = accountResult.evm_address.substring(0,42);
10391061
}
@@ -1235,7 +1257,7 @@ export class EthImpl implements Eth {
12351257
const transaction = await this.getTransactionFromContractResult(result.to, result.timestamp, requestId);
12361258
if (transaction !== null) {
12371259
transactionObjects.push(transaction);
1238-
}
1260+
}
12391261
} else {
12401262
transactionHashes.push(result.hash);
12411263
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,6 +2238,25 @@ describe('Eth calls using MirrorNode', async function () {
22382238
expect(gas).to.equal(EthImpl.gasTxBaseCost);
22392239
});
22402240

2241+
it('eth_estimateGas transfer to existing cached account', async function() {
2242+
const receiverAddress = '0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994';
2243+
restMock.onGet(`accounts/${receiverAddress}`).reply(200, { address: receiverAddress });
2244+
2245+
const gasBeforeCache = await ethImpl.estimateGas({
2246+
to: receiverAddress,
2247+
value: 100_000_000_000
2248+
}, null);
2249+
2250+
restMock.onGet(`accounts/${receiverAddress}`).reply(404);
2251+
const gasAfterCache = await ethImpl.estimateGas({
2252+
to: receiverAddress,
2253+
value: 100_000_000_000
2254+
}, null);
2255+
2256+
expect(gasBeforeCache).to.equal(EthImpl.gasTxBaseCost);
2257+
expect(gasAfterCache).to.equal(EthImpl.gasTxBaseCost);
2258+
});
2259+
22412260
it('eth_estimateGas empty call returns transfer cost', async function () {
22422261
restMock.onGet(`accounts/undefined`).reply(404);
22432262
const gas = await ethImpl.estimateGas({}, null);
@@ -3167,6 +3186,19 @@ describe('Eth', async function () {
31673186
expect(result).to.equal(null);
31683187
});
31693188

3189+
it('account should be cached', async function() {
3190+
restMock.onGet(`contracts/results/${defaultTxHash}`).reply(200, defaultDetailedContractResultByHash);
3191+
restMock.onGet(`accounts/${defaultFromLongZeroAddress}`).reply(200, {
3192+
evm_address: `${defaultTransaction.from}`
3193+
});
3194+
const resBeforeCache = await ethImpl.getTransactionByHash(defaultTxHash);
3195+
3196+
restMock.onGet(`accounts/${defaultFromLongZeroAddress}`).reply(404);
3197+
const resAfterCache = await ethImpl.getTransactionByHash(defaultTxHash);
3198+
3199+
expect(resBeforeCache).to.deep.equal(resAfterCache);
3200+
});
3201+
31703202
it('returns correct transaction for existing hash', async function () {
31713203
// mirror node request mocks
31723204
restMock.onGet(`contracts/results/${defaultTxHash}`).reply(200, defaultDetailedContractResultByHash);

0 commit comments

Comments
 (0)