Skip to content

Commit 5a129ea

Browse files
committed
feat: removed fallback predefined gas value for estimate gas when failed to retrieve gas estimate from Mirror Node
Signed-off-by: Logan Nguyen <[email protected]>
1 parent 2e9648a commit 5a129ea

File tree

8 files changed

+19
-111
lines changed

8 files changed

+19
-111
lines changed

.env.http.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ OPERATOR_KEY_MAIN= # Operator private key used to sign transaction
2222
# DEBUG_API_ENABLED=false # Enables debug methods like debug_traceTransaction
2323
# TXPOOL_API_ENABLED=true # Enables txpool related methods
2424
# FILTER_API_ENABLED=true # Enables filter related methods
25-
# ESTIMATE_GAS_THROWS=true # If true, throws actual error reason during contract reverts
2625

2726
# ========== BATCH REQUESTS ==========
2827
# BATCH_REQUESTS_ENABLED=true # Enable or disable batch requests

charts/hedera-json-rpc-relay/values.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ config:
3131
# DEBUG_API_ENABLED:
3232
# TXPOOL_API_ENABLED:
3333
# FILTER_API_ENABLED:
34-
# ESTIMATE_GAS_THROWS:
3534
# SUBSCRIPTIONS_ENABLED:
3635

3736
# ========== BATCH REQUESTS ==========

docs/configuration.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ Unless you need to set a non-default value, it is recommended to only populate o
3838
| `DEBUG_API_ENABLED` | "false" | Enables all debug related methods: `debug_traceTransaction` |
3939
| `DEFAULT_RATE_LIMIT` | "200" | default fallback rate limit, if no other is configured. |
4040
| `ENABLE_TX_POOL` | "false" | Flag to determine if the system should use a tx pool or not. |
41-
| `ESTIMATE_GAS_THROWS` | "true" | Flag to determine if the system should throw an error with the actual reason during contract reverts instead of returning a predefined gas value. |
4241
| `ETH_BLOCK_NUMBER_CACHE_TTL_MS` | "1000" | Time in ms to cache response from mirror node |
4342
| `ETH_CALL_ACCEPTED_ERRORS` | "[]" | A list of acceptable error codes for eth_call requests. If an error code in this list is returned, the request will be retried. |
4443
| `ETH_CALL_CACHE_TTL` | "200" | Maximum time in ms to cache an eth_call response. |

packages/config-service/src/services/globalConfig.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,6 @@ const _CONFIG = {
173173
required: false,
174174
defaultValue: false,
175175
},
176-
ESTIMATE_GAS_THROWS: {
177-
type: 'boolean',
178-
required: false,
179-
defaultValue: true,
180-
},
181176
ETH_BLOCK_NUMBER_CACHE_TTL_MS: {
182177
type: 'number',
183178
required: false,

packages/relay/src/lib/errors/JsonRpcError.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,12 @@ export const predefined = {
196196
message: message,
197197
});
198198
},
199-
COULD_NOT_ESTIMATE_GAS_PRICE: new JsonRpcError({
200-
code: -32604,
201-
message: 'Error encountered estimating the gas price',
202-
}),
199+
COULD_NOT_ESTIMATE_GAS_PRICE: (errMessage: string) => {
200+
return new JsonRpcError({
201+
code: -32000,
202+
message: `Error occurred during gas price estimation: ${errMessage}`,
203+
});
204+
},
203205
COULD_NOT_RETRIEVE_LATEST_BLOCK: new JsonRpcError({
204206
code: -32607,
205207
message: 'Error encountered retrieving latest block',

packages/relay/src/lib/errors/MirrorNodeClientError.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export class MirrorNodeClientError extends Error {
99

1010
static ErrorCodes = {
1111
ECONNABORTED: 504,
12-
CONTRACT_REVERT_EXECUTED: 400,
1312
NOT_SUPPORTED: 501,
1413
};
1514

@@ -45,11 +44,7 @@ export class MirrorNodeClientError extends Error {
4544
return this.statusCode === MirrorNodeClientError.ErrorCodes.ECONNABORTED;
4645
}
4746

48-
public isContractReverted(): boolean {
49-
return this.statusCode === MirrorNodeClientError.ErrorCodes.CONTRACT_REVERT_EXECUTED;
50-
}
51-
52-
public isContractRevertOpcodeExecuted() {
47+
public isContractRevert() {
5348
return this.message === MirrorNodeClientError.messages.CONTRACT_REVERT_EXECUTED;
5449
}
5550

packages/relay/src/lib/services/ethService/contractService/ContractService.ts

Lines changed: 12 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,20 @@ export class ContractService implements IContractService {
167167
try {
168168
const response = await this.estimateGasFromMirrorNode(transaction, requestDetails);
169169

170-
if (response?.result) {
171-
this.logger.info(`Returning gas: ${response.result}`);
172-
return prepend0x(trimPrecedingZeros(response.result));
173-
} else {
174-
this.logger.error(`No gas estimate returned from mirror-node: ${JSON.stringify(response)}`);
175-
return this.predefinedGasForTransaction(transaction, requestDetails);
170+
if (!response?.result) {
171+
if (this.logger.isLevelEnabled('debug')) {
172+
this.logger.debug(`No gas estimate returned from mirror-node: ${JSON.stringify(response)}`);
173+
}
174+
return predefined.INTERNAL_ERROR('Fail to retrieve gas estimate');
176175
}
176+
177+
return prepend0x(trimPrecedingZeros(response.result));
177178
} catch (e: any) {
178-
this.logger.error(`Error raised while fetching estimateGas from mirror-node: ${JSON.stringify(e)}`);
179-
// in case of contract revert, we don't want to return a predefined gas but the actual error with the reason
180-
if (
181-
ConfigService.get('ESTIMATE_GAS_THROWS') &&
182-
e instanceof MirrorNodeClientError &&
183-
e.isContractRevertOpcodeExecuted()
184-
) {
185-
return predefined.CONTRACT_REVERT(e.detail ?? e.message, e.data);
179+
if (e instanceof MirrorNodeClientError && e.isContractRevert()) {
180+
throw predefined.CONTRACT_REVERT(e.detail || e.message, e.data);
181+
} else {
182+
throw predefined.COULD_NOT_ESTIMATE_GAS_PRICE(e.detail || e.message);
186183
}
187-
return this.predefinedGasForTransaction(transaction, requestDetails, e);
188184
}
189185
}
190186

@@ -523,7 +519,7 @@ export class ContractService implements IContractService {
523519
return constants.EMPTY_HEX;
524520
}
525521

526-
if (e.isContractReverted()) {
522+
if (e.isContractRevert()) {
527523
if (this.logger.isLevelEnabled('trace')) {
528524
this.logger.trace(
529525
`mirror node eth_call request encountered contract revert. message: ${e.message}, details: ${e.detail}, data: ${e.data}`,
@@ -555,68 +551,6 @@ export class ContractService implements IContractService {
555551
return predefined.INTERNAL_ERROR(e.message.toString());
556552
}
557553

558-
/**
559-
* Fallback calculations for the amount of gas to be used for a transaction.
560-
* This method is used when the mirror node fails to return a gas estimate.
561-
*
562-
* @param {IContractCallRequest} transaction The transaction data for the contract call.
563-
* @param {RequestDetails} requestDetails The request details for logging and tracking.
564-
* @param error (Optional) received error from the mirror-node contract call request.
565-
* @returns {Promise<string | JsonRpcError>} the calculated gas cost for the transaction
566-
*/
567-
private async predefinedGasForTransaction(
568-
transaction: IContractCallRequest,
569-
requestDetails: RequestDetails,
570-
error?: any,
571-
): Promise<string | JsonRpcError> {
572-
const isSimpleTransfer = !!transaction?.to && (!transaction.data || transaction.data === '0x');
573-
const isContractCall =
574-
!!transaction?.to && transaction?.data && transaction.data.length >= constants.FUNCTION_SELECTOR_CHAR_LENGTH;
575-
const isContractCreate = !transaction?.to && transaction?.data && transaction.data !== '0x';
576-
const contractCallAverageGas = numberTo0x(constants.TX_CONTRACT_CALL_AVERAGE_GAS);
577-
const gasTxBaseCost = numberTo0x(constants.TX_BASE_COST);
578-
579-
if (isSimpleTransfer) {
580-
// Handle Simple Transaction and Hollow Account creation
581-
const isZeroOrHigher = Number(transaction.value) >= 0;
582-
if (!isZeroOrHigher) {
583-
return predefined.INVALID_PARAMETER(
584-
0,
585-
`Invalid 'value' field in transaction param. Value must be greater than or equal to 0`,
586-
);
587-
}
588-
// when account exists return default base gas
589-
if (await this.common.getAccount(transaction.to!, requestDetails)) {
590-
this.logger.warn(`Returning predefined gas for simple transfer: ${gasTxBaseCost}`);
591-
return gasTxBaseCost;
592-
}
593-
const minGasTxHollowAccountCreation = numberTo0x(constants.MIN_TX_HOLLOW_ACCOUNT_CREATION_GAS);
594-
// otherwise, return the minimum amount of gas for hollow account creation
595-
this.logger.warn(`Returning predefined gas for hollow account creation: ${minGasTxHollowAccountCreation}`);
596-
return minGasTxHollowAccountCreation;
597-
} else if (isContractCreate) {
598-
// The size limit of the encoded contract posted to the mirror node can
599-
// cause contract deployment transactions to fail with a 400 response code.
600-
// The contract is actually deployed on the consensus node, so the contract will work.
601-
// In these cases, we don't want to return a CONTRACT_REVERT error.
602-
if (
603-
ConfigService.get('ESTIMATE_GAS_THROWS') &&
604-
error?.isContractReverted() &&
605-
error?.message !== MirrorNodeClientError.messages.INVALID_HEX
606-
) {
607-
return predefined.CONTRACT_REVERT(error.detail, error.data);
608-
}
609-
this.logger.warn(`Returning predefined gas for contract creation: ${gasTxBaseCost}`);
610-
return numberTo0x(Precheck.transactionIntrinsicGasCost(transaction.data!));
611-
} else if (isContractCall) {
612-
this.logger.warn(`Returning predefined gas for contract call: ${contractCallAverageGas}`);
613-
return contractCallAverageGas;
614-
} else {
615-
this.logger.warn(`Returning predefined gas for unknown transaction: ${this.defaultGas}`);
616-
return this.defaultGas;
617-
}
618-
}
619-
620554
/**
621555
* Prepares the call data for mirror node request.
622556
*

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -396,21 +396,6 @@ describe('@ethEstimateGas Estimate Gas spec', async function () {
396396
expect(estimatedGas).to.equal(numberTo0x(Precheck.transactionIntrinsicGasCost(transaction.data!)));
397397
});
398398

399-
withOverriddenEnvsInMochaTest({ ESTIMATE_GAS_THROWS: 'false' }, () => {
400-
it('should eth_estimateGas with contract revert and message does not equal executionReverted and ESTIMATE_GAS_THROWS is set to false', async function () {
401-
const originalEstimateGas = contractService.estimateGas;
402-
contractService.estimateGas = async () => {
403-
return numberTo0x(Precheck.transactionIntrinsicGasCost(transaction.data!));
404-
};
405-
406-
const result = await ethImpl.estimateGas(transaction, id, requestDetails);
407-
408-
expect(result).to.equal(numberTo0x(Precheck.transactionIntrinsicGasCost(transaction.data!)));
409-
410-
contractService.estimateGas = originalEstimateGas;
411-
});
412-
});
413-
414399
it('should eth_estimateGas with contract revert and message equals "execution reverted: Invalid number of recipients"', async function () {
415400
await mockContractCall(
416401
transaction,

0 commit comments

Comments
 (0)