Skip to content

Conversation

@quiet-node
Copy link
Contributor

@quiet-node quiet-node commented Dec 3, 2025

Description

This PR fixes inconsistent error handling in eth_estimateGas by removing the fallback gas behavior that masked legitimate errors.

Problem: Previously, when the Mirror Node returned any error other than CONTRACT_REVERT_EXECUTED, the Relay would silently return a predefined fallback gas estimate. This hid real errors from users, who would then submit transactions that were guaranteed to fail on-chain.

Solution: This PR enables the Relay now properly propagates errors according to industry standards (aligned with Geth, Besu, and major providers):

  • Contract reverts → code 3 (CONTRACT_REVERT)
  • 400 errors (non-revert, validation failures) → code -32000 (COULD_NOT_SIMULATE_TRANSACTION)
  • 429, 5xx errors → re-thrown to preserve original error context and handled at dispatch level

Related issue(s)

Fixes #4459

Testing Guide

  1. Contract revert scenario:

    • Call eth_estimateGas on a contract function that reverts
    • Expected: Error with code 3 and revert message
  2. Non-existent sender account:

    • Call eth_estimateGas with a from address that doesn't exist on the network
    • Expected: Error with code -32000 and message containing "Error occurred during transaction simulation"
  3. Valid gas estimation:

    • Call eth_estimateGas with valid from/to addresses and valid contract call data
    • Expected: Returns gas estimate as before

Changes from original design (optional)

  • Combined MirrorNodeClientError isContractReverted() & isContractRevertOpcodeExecuted() into isContractRevert(), make sure it checks for CONTRACT_REVERT_EXECUTED message explicitly
  • With the new logic of CONTRACT_REVERT for eth_estimateGas, eth_call errors are also updated to align:
    • If truly CONTRACT_REVERT -> return code 3
    • If 400 from MN -> return code -32000
    • If 429, 5xx -> return re-thrown to preserve original error context and handled at dispatch level

Additional work needed (optional)

N/A

Checklist

  • I've assigned an assignee to this PR and related issue(s) (if applicable)
  • I've assigned a label to this PR and related issue(s) (if applicable)
  • I've assigned a milestone to this PR and related issue(s) (if applicable)
  • I've updated documentation (code comments, README, etc. if applicable)
  • I've done sufficient testing (unit, integration, etc.)

…led to retrieve gas estimate from Mirror Node

Signed-off-by: Logan Nguyen <[email protected]>
Signed-off-by: Logan Nguyen <[email protected]>
Signed-off-by: Logan Nguyen <[email protected]>
@quiet-node quiet-node added this to the 0.74.0 milestone Dec 3, 2025
@quiet-node quiet-node self-assigned this Dec 3, 2025
@quiet-node quiet-node added the enhancement New feature or request label Dec 3, 2025
@github-actions
Copy link

github-actions bot commented Dec 3, 2025

Test Results

 20 files  ±0  274 suites  +2   22m 2s ⏱️ +22s
798 tests +7  794 ✅ +8  4 💤 ±0  0 ❌  - 1 
814 runs  +7  810 ✅ +8  4 💤 ±0  0 ❌  - 1 

Results for commit e090cab. ± Comparison against base commit 2e9648a.

This pull request removes 4 and adds 11 tests. Note that renamed tests count towards both.
@release-light, @release should execute "eth_estimateGas" ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas @release-light, @release should execute "eth_estimateGas"
should execute "eth_estimateGas" with `to` filed set to null (deployment transaction) ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas should execute "eth_estimateGas" with `to` filed set to null (deployment transaction)
should execute "eth_estimateGas" with to, from, value and gas filed ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas should execute "eth_estimateGas" with to, from, value and gas filed
should execute "eth_estimateGas" with to, from, value,accessList gas filed ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas should execute "eth_estimateGas" with to, from, value,accessList gas filed
@release-light, @release should execute "eth_estimateGas" with empty object and throw error ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas @release-light, @release should execute "eth_estimateGas" with empty object and throw error
should execute "eth_estimateGas" with `to` field set to null (deployment transaction) ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas should execute "eth_estimateGas" with `to` field set to null (deployment transaction)
should execute "eth_estimateGas" with to, from, value and gas field ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas should execute "eth_estimateGas" with to, from, value and gas field
should execute "eth_estimateGas" with to, from, value, accessList and gas field ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas should execute "eth_estimateGas" with to, from, value, accessList and gas field
should throw COULD_NOT_SIMULATE_TRANSACTION error when "to" field is empty for contract call ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas Gas estimation errors (non-contract revert) should throw COULD_NOT_SIMULATE_TRANSACTION error when "to" field is empty for contract call
should throw COULD_NOT_SIMULATE_TRANSACTION error when sender account does not exist ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas Gas estimation errors (non-contract revert) should throw COULD_NOT_SIMULATE_TRANSACTION error when sender account does not exist
should throw error when eth_estimateGas is called with a contract that reverts with custom error ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas Contract call reverts during gas estimation should throw error when eth_estimateGas is called with a contract that reverts with custom error
should throw error when eth_estimateGas is called with a contract that reverts with panic error ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas Contract call reverts during gas estimation should throw error when eth_estimateGas is called with a contract that reverts with panic error
should throw error when eth_estimateGas is called with a contract that reverts with string message ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas Contract call reverts during gas estimation should throw error when eth_estimateGas is called with a contract that reverts with string message
should throw error when eth_estimateGas is called with a contract that reverts without message ‑ RPC Server Acceptance Tests Acceptance tests @api-batch-2 RPC Server Acceptance Tests eth_estimateGas Contract call reverts during gas estimation should throw error when eth_estimateGas is called with a contract that reverts without message
…

♻️ This comment has been updated with latest results.

@quiet-node quiet-node force-pushed the 4459-inconsistent-mirror-node-responses-for-contractscall-when-value-field-is-omitted-in-hts-transfer-estimation branch 2 times, most recently from ba724a6 to 73e81bd Compare December 4, 2025 18:42
@quiet-node quiet-node force-pushed the 4459-inconsistent-mirror-node-responses-for-contractscall-when-value-field-is-omitted-in-hts-transfer-estimation branch from 96c154f to d2ff67c Compare December 4, 2025 19:17
# DEBUG_API_ENABLED:
# TXPOOL_API_ENABLED:
# FILTER_API_ENABLED:
# ESTIMATE_GAS_THROWS:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewers: Since estimateGas no longer falls back to predefined gas and always throws, the ESTIMATE_GAS_THROWS config no longer has any meaningful effect, so it has been removed.

return this.statusCode === MirrorNodeClientError.ErrorCodes.CONTRACT_REVERT_EXECUTED;
}

public isContractRevertOpcodeExecuted() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewers: These two are now consolidated into a single method, isContractRevert(), which explicitly checks for the error.message === MirrorNodeClientError.messages.CONTRACT_REVERT_EXECUTED instead of falling back to a 400 status code as before, which wasn't accurate since not all 400 errors indicate a contract revert.

}

throw predefined.COULD_NOT_ESTIMATE_GAS_PRICE;
throw predefined.INTERNAL_ERROR('Failed to retrieve gas price from network fees');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewers: Previously, this was thrown as COULD_NOT_ESTIMATE_GAS_PRICE, which was inaccurate since this method is used for eth_gasPrice, not estimation. I’ve updated it to use INTERNAL_ERROR instead, as reaching this point indicates an unexpected code issue rather than a gas-related problem from the Mirror Node.

message: `Error occurred during transaction simulation: ${errMessage}`,
});
},
COULD_NOT_RETRIEVE_LATEST_BLOCK: new JsonRpcError({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewers: Renamed to COULD_NOT_SIMULATE_TRANSACTION so it can be used for both eth_estimateGas and eth_call when they encounter issues submitting requests to the Mirror Node’s /call endpoint, which handles transaction simulation under the hood.

@quiet-node quiet-node force-pushed the 4459-inconsistent-mirror-node-responses-for-contractscall-when-value-field-is-omitted-in-hts-transfer-estimation branch from d2ff67c to e090cab Compare December 4, 2025 20:03
@codecov
Copy link

codecov bot commented Dec 4, 2025

Codecov Report

❌ Patch coverage is 87.09677% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ices/ethService/contractService/ContractService.ts 82.60% 4 Missing ⚠️
@@            Coverage Diff             @@
##             main    #4678      +/-   ##
==========================================
- Coverage   95.47%   95.43%   -0.05%     
==========================================
  Files         129      129              
  Lines       20928    20859      -69     
  Branches     1793     1790       -3     
==========================================
- Hits        19982    19906      -76     
- Misses        926      934       +8     
+ Partials       20       19       -1     
Flag Coverage Δ
config-service 98.82% <ø> (-0.01%) ⬇️
relay 90.89% <77.41%> (+0.01%) ⬆️
server 88.99% <ø> (ø)
ws-server 97.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ckages/config-service/src/services/globalConfig.ts 100.00% <ø> (ø)
packages/relay/src/lib/errors/JsonRpcError.ts 96.93% <100.00%> (+0.02%) ⬆️
...ages/relay/src/lib/errors/MirrorNodeClientError.ts 94.87% <100.00%> (-0.31%) ⬇️
...vices/ethService/ethCommonService/CommonService.ts 95.50% <100.00%> (ø)
...ices/ethService/contractService/ContractService.ts 93.82% <82.60%> (-0.12%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent Mirror Node responses for contracts/call when value field is omitted in HTS transfer estimation

2 participants