Summary
The documentation states:
When true, the eth_simulateV1 does all the validation that a normal EVM would do, except contract sender and signature checks.
On an Osaka, pre-Amsterdam chain, a normal transaction whose gas limit exceeds the EIP-7825 cap is rejected, but the same call succeeds through eth_simulateV1 with validation: true when the simulated block gas limit is raised.
The simulator passes the validation option into its nonce-check behavior, but TransactionArgs.ToMessage still sets SkipTransactionChecks: true unconditionally. This bypasses the EIP-7825 transaction gas-limit check as well as the documented contract-sender exception.
Documentation: https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#eth-simulate-v1
System information
- Runtime reproduction: Geth
1.17.5-unstable, commit 81ab8b594ebe0f672450779d4b308f3f33191828
- Platform: macOS arm64, Go
1.26.3
- Chain rules: Osaka active, Amsterdam inactive
- Node mode: disposable
--dev node with --rpc.gascap 0
- The same implementation mechanism is still present on
master at 7e520c43104fd0447acd7372a63ba1daa5c05929 (checked 2026-08-08).
Steps to reproduce
Build commit 81ab8b594ebe0f672450779d4b308f3f33191828 and start a dev node:
./build/bin/geth \
--dev \
--http \
--http.addr 127.0.0.1 \
--http.port 8545 \
--http.api eth,web3 \
--rpc.gascap 0 \
--ipcdisable
In another shell, use the first address returned by eth_accounts as DEV:
#!/usr/bin/env bash
set -euo pipefail
RPC_URL="${RPC_URL:-http://127.0.0.1:8545}"
curl -sS -H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_accounts","params":[]}' \
"$RPC_URL"
# Default --dev account in the reproduced run. Replace this if eth_accounts
# prints a different address.
DEV="${DEV:-0x71562b71999873db5b286df957af199ec94617f7}"
echo '=== normal transaction path ==='
curl -sS -H 'Content-Type: application/json' --data "{
\"jsonrpc\":\"2.0\",
\"id\":2,
\"method\":\"eth_sendTransaction\",
\"params\":[{
\"from\":\"$DEV\",
\"to\":\"$DEV\",
\"gas\":\"0x1100000\",
\"gasPrice\":\"0x2540be400\",
\"value\":\"0x0\"
}]
}" "$RPC_URL"
echo
echo '=== eth_simulateV1 with validation=true ==='
curl -sS -H 'Content-Type: application/json' --data "{
\"jsonrpc\":\"2.0\",
\"id\":3,
\"method\":\"eth_simulateV1\",
\"params\":[{
\"validation\":true,
\"blockStateCalls\":[{
\"blockOverrides\":{\"gasLimit\":\"0x2000000\"},
\"calls\":[{
\"from\":\"$DEV\",
\"to\":\"$DEV\",
\"gas\":\"0x1100000\",
\"gasPrice\":\"0x2540be400\",
\"value\":\"0x0\"
}]
}]
},\"latest\"]
}" "$RPC_URL"
echo
Observed behavior
The normal transaction path rejects the transaction:
{
"error": {
"code": -32000,
"message": "transaction gas limit too high (cap: 16777216, tx: 17825792)"
}
}
The simulation with validation: true accepts the same gas limit and reports successful execution:
{
"result": [{
"gasLimit": "0x2000000",
"calls": [{"status": "0x1", "gasUsed": "0x5208"}]
}]
}
The block override only prevents the unrelated simulated block gas pool from failing first. The transaction gas limit (0x1100000) remains above the normal Osaka cap (0x1000000).
Expected behavior
With validation: true, the simulated call should fail the same EIP-7825 transaction gas-limit validation as the normal transaction path. The documented exceptions cover contract senders and signatures, not the transaction gas-limit cap.
Relevant code
Impact
Applications can treat a simulation as transaction-valid even though the normal transaction path rejects the same transaction. This can produce incorrect preflight, transaction-construction, and risk decisions.
Suggested direction
Represent nonce-check skipping and transaction-check skipping independently. In simulation validation mode, retain only the explicitly documented exceptions and allow the normal transaction gas-limit check to run.
Summary
The documentation states:
On an Osaka, pre-Amsterdam chain, a normal transaction whose gas limit exceeds the EIP-7825 cap is rejected, but the same call succeeds through
eth_simulateV1withvalidation: truewhen the simulated block gas limit is raised.The simulator passes the
validationoption into its nonce-check behavior, butTransactionArgs.ToMessagestill setsSkipTransactionChecks: trueunconditionally. This bypasses the EIP-7825 transaction gas-limit check as well as the documented contract-sender exception.Documentation: https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#eth-simulate-v1
System information
1.17.5-unstable, commit81ab8b594ebe0f672450779d4b308f3f331918281.26.3--devnode with--rpc.gascap 0masterat7e520c43104fd0447acd7372a63ba1daa5c05929(checked 2026-08-08).Steps to reproduce
Build commit
81ab8b594ebe0f672450779d4b308f3f33191828and start a dev node:In another shell, use the first address returned by
eth_accountsasDEV:Observed behavior
The normal transaction path rejects the transaction:
{ "error": { "code": -32000, "message": "transaction gas limit too high (cap: 16777216, tx: 17825792)" } }The simulation with
validation: trueaccepts the same gas limit and reports successful execution:{ "result": [{ "gasLimit": "0x2000000", "calls": [{"status": "0x1", "gasUsed": "0x5208"}] }] }The block override only prevents the unrelated simulated block gas pool from failing first. The transaction gas limit (
0x1100000) remains above the normal Osaka cap (0x1000000).Expected behavior
With
validation: true, the simulated call should fail the same EIP-7825 transaction gas-limit validation as the normal transaction path. The documented exceptions cover contract senders and signatures, not the transaction gas-limit cap.Relevant code
internal/ethapi/simulate.go:327-351:validationaffects the nonce-check argument passed toToMessage.internal/ethapi/transaction_args.go:491-507:SkipTransactionChecksis always set totrue.core/state_transition.go:561-570: the EIP-7825 check is guarded by!msg.SkipTransactionChecks.Impact
Applications can treat a simulation as transaction-valid even though the normal transaction path rejects the same transaction. This can produce incorrect preflight, transaction-construction, and risk decisions.
Suggested direction
Represent nonce-check skipping and transaction-check skipping independently. In simulation validation mode, retain only the explicitly documented exceptions and allow the normal transaction gas-limit check to run.