eth_call returns the bytes produced by a simulated Ethereum contract call; eth_estimateGas returns an estimated gas limit for a proposed execution. Neither method broadcasts a transaction or saves simulated state changes to the chain. Success applies to the request and state you supplied. It does not prove that you can sign the transaction, that it will be included, or that its later execution will produce the same result.
Two responses that answer different questions
A preview needs two separate interpretations: what the contract returned, and how much gas an execution might require. Ethereum's JSON-RPC reference describes eth_call as execution without creating a blockchain transaction. Its response contains return data. Gas estimation also runs without adding the proposed transaction to the chain, but its response is a gas quantity.
| Observation | eth_call | eth_estimateGas |
|---|---|---|
| Main question | What does this call return in the selected context? | What gas limit does the estimator find for execution in this context? |
| Normal result | Contract return bytes | Hexadecimal gas quantity |
| Simulated writes | May occur during execution; not committed to the chain | May occur during estimation; not committed to the chain |
| Contract revert | Can produce an RPC error with revert data | Can prevent a successful estimate |
| Evidence still needed | Correct decoding and intended business result | Gas policy, eventual inclusion and actual receipt |
The current execution API schema defines different result types for the two methods and documents execution-reverted errors. A gas quantity is not the function's returned token amount, Boolean or remaining balance.
Decode call results using the intended function's ABI. Solidity's ABI specification explains that the encoding needs a schema. A function returning a uint256 value of 5 produces 31 zero bytes followed by byte 0x05, forming one 32-byte word. A normal return of false is also possible: the contract need not revert merely because the application's desired condition was not met. An empty 0x result means empty return bytes; check the target and expected interface before interpreting it as a completed action.
Follow one proposed call without committing it
Consider a hypothetical inventory contract with eight units in stock. Its function take(units) first requires stock to be at least the requested quantity, then subtracts that quantity and returns the remaining stock as a uint256. There are no other conditions in this teaching model.
The proposed call requests three units. Let B identify one fixed block and its resulting state. Assume the endpoint supports both methods against that state, with the same sender, target and input, adequate gas allowances, and no state or block overrides. No included calls other than the ones shown change inventory.
All values below are invented. In particular, the 50,000-gas estimate is an illustrative response, not an EVM measurement or a claim about this function's real cost.
| Step | Starting stock used | Result of execution or estimation | Canonical contract stock afterward |
|---|---|---|---|
| eth_call for take(3) at B | 8 | Temporary stock 5; decoded return 5 | 8 |
| eth_estimateGas for take(3) at B | 8 | Illustrative estimate 0xc350, or 50,000 gas | 8 |
| Another eth_call for take(3) at B | 8 | Decoded return 5 again | 8 |
| A separate transaction taking 6 is included later | 8 | Its successful write leaves 2 | 2 |
| The original take(3) is included after that transaction | 2 | Requirement fails; execution reverts | 2 |
The first subtraction is 8 − 3 = 5. Because neither RPC request commits that write, the next request at B starts from eight again. It does not start from five and return two. The later included transaction instead commits 8 − 6 = 2. At that point, two is less than three, so the original request's inventory condition fails.
Giving the last transaction a larger gas limit cannot make two units satisfy a three-unit requirement. The failed condition is stock availability. The earlier successful estimate answered a question about the earlier state.
The hexadecimal conversion is also reproducible: 0xc350 equals 12 × 4,096 + 3 × 256 + 5 × 16, which is 50,000. Those are gas units, not wei, ETH or units of inventory. Nothing in this ledger establishes a final fee.
The stock column deliberately tracks only contract inventory. An included revert can still have an execution fee and affect the sender's transaction sequence. The failed-swap gas ledger explains those receipt-based charges separately.
A simulated approval does not prepare the next request
The same boundary matters when an operation has prerequisites. Calling an approval function through eth_call does not establish an on-chain allowance for a separate swap simulation. The next independent request starts from its selected chain state, without inheriting that earlier temporary approval.
Geth's eth_call documentation describes testing contract validations and transaction effects without running them live. “Without running them live” includes the writes that would have prepared a later action.
If a tool previews a sequence, determine whether it actually carries simulated state between the steps. Several independent RPC requests are not automatically one sequential execution. Likewise, an override that supplies a missing allowance demonstrates a conditional scenario; it does not show that the real prerequisite already exists.
Preserve the request, not just the green result
The sender can change the execution path. Geth's transaction call object defines from as the address the transaction is simulated to have been sent from. Setting that field does not demonstrate control of the account's signing key. An omitted sender may also receive a client-specific default.
Preserve the intended sender, destination, input bytes and value. Include the gas allowance, applicable fee fields and other transaction fields that affect the proposed execution. Compare what the application simulated with what the wallet eventually asks you to authorize. A changed recipient or argument is a changed request, even when the interface retains the same description.
A successful response is not a funding certificate either. When fee fields are omitted, the current execution schema permits client-selected fee defaults and disallows failure solely because the sender cannot afford those defaults. This does not waive balance requirements for nonzero value. Validate funding for the real transaction separately, using its actual fields.
State selection needs the same care. The execution API schema defines block selectors for both methods and describes the selected state as the state after the block has executed. Confirm which selector forms your endpoint supports. EIP-1898 specifically defines block-hash selection for eth_call; its requireCanonical option adds a canonical-chain requirement. Do not infer an endpoint's estimation support from that EIP alone.
When comparing results, resolve and record the block identity rather than saving only the word “latest.” The batch-request and block-snapshot guide explains how to keep several reads tied to one observation. Reproducibility at an old block still does not preserve that state for future inclusion.
A gas estimate is neither an exact bill nor a repair
An estimate depends on the execution path and the estimator's search. For example, the Geth estimator source, inspected for this guide on 28 October 2026, searches for a successful gas limit and permits an overestimation tolerance. That is one implementation's behavior, not a promise that every provider returns an identical mathematical minimum.
Distinguish three quantities: the estimate, the gas limit eventually authorized, and the actual gas used reported after inclusion. Ethereum's gas-estimation reference explicitly warns that an estimate can exceed actual usage. Multiplying an estimate by an assumed price produces a planning figure, not a settled charge.
The supplied gas allowance also matters when comparing methods. Geth's estimation implementation applies request and RPC gas caps. A call tested with a generous allowance and an estimate constrained by a lower cap have different assumptions. Preserve those inputs before concluding that the methods disagree about the contract.
For a swap, a changed reserve, allowance or time condition can alter execution before inclusion. The deadline and slippage comparison shows how two independent contract conditions can fail. A gas cushion cannot repair an expired deadline or authorize an output below the signed minimum.
Separate execution errors from missing evidence
A revert is useful evidence about the supplied call and context. Save the error and any return data, decode it against the appropriate interface, and identify the failed condition. Do not translate every estimation error into “the transaction is impossible.”
The request might instead lack accessible historical state, exceed an endpoint's computation limits, contain unsupported parameters or fail transport. Geth's published command-line reference illustrates this distinction: its displayed 1.15.11 help listing includes an RPC gas cap and an eth_call execution timeout. Check the limits of the client version and provider you actually use.
Record state and block overrides separately. Geth's override definitions cover balances, code, storage and block context. A successful preview with modified state supports “this worked under the override.” It does not establish that the unmodified chain supports the same action. Re-run against the intended real context before using that result in an authorization decision.
Keep a preflight record that can be reconciled
Use a compact worksheet instead of saving a screenshot of “simulation successful.”
| Record | What to preserve |
|---|---|
| Execution context | Chain, endpoint, client version when available, block number and hash |
| Proposed action | Sender, target, function, exact input, value and recipient |
| Simulation conditions | Gas and fee fields, relevant transaction fields, state and block overrides |
| eth_call evidence | Raw return bytes or error, ABI used, decoded interpretation |
| Estimation evidence | Raw gas quantity or error, decimal conversion, known endpoint limits |
| Authorization | Final transaction fields, differences from the preview and reason for accepting them |
| Included outcome | Transaction hash, receipt, verified business result and confirmation policy |
After inclusion, reconcile the actual transaction and receipt. If the action uses emitted events, keep their block and event identity with the transaction; the transaction-hash versus log-index guide explains that distinction. A preview's return data is not an included event or proof of a completed transfer.
Before authorizing, make one final comparison: does the proposed transaction still match the request, state assumptions and absolute bounds you reviewed? If any material input changed, record a fresh call and estimate. Preserve both responses with their context, then close the record using the included outcome.
