Skip to content

t8n: currentGasLimit >= 2^63 wraps signed and rejects valid txs #1484

@chfast

Description

@chfast

Summary

evmone-t8n treats env.currentGasLimit as signed int64_t (via JSON loader), so values >= 2^63 wrap negative and cause valid transactions to be rejected as "gas limit reached".

go-ethereum evm t8n treats currentGasLimit as uint64 and executes the same transaction.

Reproducer (Cancun)

alloc.json

{
  "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
    "code": "0x",
    "nonce": "0x0",
    "balance": "0xde0b6b3a7640000",
    "storage": {}
  }
}

env.json

{
  "currentCoinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1",
  "currentNumber": "0x01",
  "currentTimestamp": "0x54c99069",
  "currentGasLimit": "0x8000000000000000",
  "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000000001",
  "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "currentBaseFee": "0x1",
  "currentExcessBlobGas": "0x0",
  "withdrawals": []
}

txs.json

[
  {
    "to": "0x095E7BAea6a6c7c4c2DfeB977eFac326aF552d87",
    "input": "0x",
    "gas": "0x5208",
    "nonce": "0x0",
    "value": "0x0",
    "gasPrice": "0x1",
    "chainId": "0x1",
    "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
    "v": "0x26",
    "r": "0x62d32a1bac6b89021fce16cf51479a8b00f26523933afde1b62f7957ed1943a3",
    "s": "0x6f3941435cb48b0c649c1b0d707fc6878407f6287c9cd89c33c0048bd2710e45"
  }
]

Commands

# evmone
evmone-t8n \
  --state.fork Cancun --state.chainid 1 \
  --input.alloc alloc.json --input.env env.json --input.txs txs.json \
  --output.basedir out-evmone --output.result result.json --output.alloc alloc.json

# geth
evm t8n \
  --state.fork Cancun --state.chainid 1 \
  --input.alloc alloc.json --input.env env.json --input.txs txs.json \
  --output.basedir out-geth --output.result result.json --output.alloc alloc.json

Observed divergence

  • evmone:
    • rejected[0].error = "gas limit reached"
    • gasUsed = 0x0
    • empty tx/receipt roots (0x56e81f...)
  • geth:
    • tx executes successfully
    • gasUsed = 0x5208
    • non-empty tx/receipt roots

State roots differ:

  • evmone: 0x517f2cdf6adb1a644878c390ffab4e130f1bed4b498ef7ce58c5addd98d61018
  • geth: 0x5a605f957d4aa4145411d63287ddf1bae2202c30cc6ec86ae003423bb6343778

Control (boundary)

If only currentGasLimit is changed to 0x7fffffffffffffff (2^63 - 1), evmone and geth agree and both execute the tx.

This isolates the issue to signed handling above int64 max.

Suspected root cause

currentGasLimit and tx gas are parsed via from_json<int64_t> using unsigned parse + signed cast:

  • test/utils/statetest_loader.cpp
    • integer_from_json<T> uses static_cast<T>(std::stoull(...))
    • block field assignment: .gas_limit = from_json<int64_t>(j.at("currentGasLimit"))

Execution path then uses signed comparison:

  • test/t8n/t8n.cpp: int64_t block_gas_left = block.gas_limit;
  • test/state/state.cpp: if (tx.gas_limit > block_gas_left) return GAS_LIMIT_REACHED;

For 0x8000000000000000, block_gas_left becomes negative, causing false rejection.

For reference, geth t8n env models currentGasLimit as uint64:

  • cmd/evm/internal/t8ntool/execution.go: GasLimit uint64 \json:"currentGasLimit"``

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions