Skip to content

eth_simulateV1 with validation: true skips the EIP-7825 transaction gas-limit check #35479

Description

@BenWhite713

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions