Skip to content

Prague/Osaka set-code tx can skip top-level execution when sender nonce reaches 2^64-1 pre-execution #1496

@chfast

Description

@chfast

Summary

Found a canonical consensus divergence in the set-code tx flow (EIP-7702 path), reproducible on Prague and Osaka.

If:

  • sender initial nonce is 2^64-3 (0xfffffffffffffffd),
  • tx nonce is 2^64-3,
  • tx is type 0x4 (set-code),
  • authorization list contains a tuple signed by the sender with nonce 2^64-2,

then evmone-statetest / evmone-t8n skip top-level execution after nonce reaches 2^64-1 pre-execution, while geth executes normally.

This yields different stateRoot / receiptsRoot / gasUsed.


Minimal Osaka state test

{
  "statetest_nonce_maxminus2_osaka_setcode_senderauth": {
    "_info": {
      "comment": "Osaka: sender nonce=2^64-3 and sender-authorized tuple nonce=2^64-2. Top-level call should execute."
    },
    "env": {
      "currentCoinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1",
      "currentNumber": "0x1",
      "currentTimestamp": "0x54c99069",
      "currentGasLimit": "0x5f5e100",
      "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000000001",
      "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "currentBaseFee": "0x1",
      "currentExcessBlobGas": "0x0",
      "withdrawals": []
    },
    "config": {
      "blobSchedule": {
        "Cancun": {
          "target": "0x03",
          "max": "0x06",
          "baseFeeUpdateFraction": "0x32f0ed"
        },
        "Prague": {
          "target": "0x06",
          "max": "0x09",
          "baseFeeUpdateFraction": "0x4c6964"
        },
        "Osaka": {
          "target": "0x06",
          "max": "0x09",
          "baseFeeUpdateFraction": "0x4c6964"
        }
      }
    },
    "pre": {
      "0x1cb29f6b656a8ae0f6c1a3352b2daa7dc5b71393": {
        "nonce": "0xfffffffffffffffd",
        "balance": "0xffffffffffffffffffffffffffffffff",
        "code": "0x",
        "storage": {}
      },
      "0x1000000000000000000000000000000000000000": {
        "nonce": "0x0",
        "balance": "0x0",
        "code": "0x600160005500",
        "storage": {}
      },
      "0x3333333333333333333333333333333333333333": {
        "nonce": "0x0",
        "balance": "0x0",
        "code": "0x00",
        "storage": {}
      },
      "0x0000f90827f1c53a10cb7a02335b175320002935": {
        "code": "0x00",
        "nonce": "0x1",
        "balance": "0x0",
        "storage": {}
      },
      "0x00000961ef480eb55e80d19ad83579a64c007002": {
        "code": "0x00",
        "nonce": "0x1",
        "balance": "0x0",
        "storage": {}
      },
      "0x0000bbddc7ce488642fb579f8b00f3a590007251": {
        "code": "0x00",
        "nonce": "0x1",
        "balance": "0x0",
        "storage": {}
      }
    },
    "transaction": {
      "data": [
        "0x"
      ],
      "gasLimit": [
        "0x186a0"
      ],
      "value": [
        "0x0"
      ],
      "to": "0x1000000000000000000000000000000000000000",
      "nonce": "0xfffffffffffffffd",
      "chainId": "0x1",
      "maxFeePerGas": "0x1",
      "maxPriorityFeePerGas": "0x0",
      "authorizationList": [
        {
          "address": "0x3333333333333333333333333333333333333333",
          "chainId": "0x1",
          "nonce": "0xfffffffffffffffe",
          "r": "0x7fe003d3659d16f919fa86bebe32db3c7e1654185c79f41218bcedaf56872da2",
          "s": "0x1a3e84eba2c23991fc552efd883aca3596212dd86272d7e35f0555f3e7ed26d1",
          "signer": "0x1cb29f6b656A8ae0f6C1A3352B2DaA7DC5b71393",
          "v": "0x1"
        }
      ],
      "type": "0x4",
      "sender": "0x1cb29f6b656a8ae0f6c1a3352b2daa7dc5b71393",
      "secretKey": "0x45a915e4d060149eb4365960e6a7a45f3343930930608de2f8f5ad2d16fbb53f"
    },
    "post": {
      "Osaka": [
        {
          "indexes": {
            "data": 0,
            "gas": 0,
            "value": 0
          },
          "hash": "0x10db88c7413e8962777938cbf2e202affc227313216864c68105111d1ae04066",
          "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
        }
      ]
    }
  }
}

Commands

# geth
evm statetest nonce_maxminus2_setcode_senderauth_osaka_state_test.json

# evmone
evmone-statetest nonce_maxminus2_setcode_senderauth_osaka_state_test.json

Observed

  • geth: passes, stateRoot = 0x10db88c7413e8962777938cbf2e202affc227313216864c68105111d1ae04066
  • evmone: fails with computed root 0x28825352fc5aeb3038cf139696747c189dcd5d863ce6b61f35e725df6875cc28

For the equivalent Prague t8n repro:

  • geth: gasUsed=0xd936
  • evmone: gasUsed=0x8fc0
  • stateRoot and receiptsRoot differ as well.

Likely root-cause path

This looks like the same depth-0 nonce re-check family as #1495, but triggered through EIP-7702 authorization processing:

  1. transition() bumps sender nonce before top-level execution.
  2. process_authorization_list() can bump the same account nonce again when sender == authority.
  3. sender nonce reaches NonceMax before top-level message execution.
  4. Host::prepare_message() checks sender_acc.nonce == Account::NonceMax even at depth 0 and returns light failure.

Relevant areas:

  • test/state/state.cpp (sender nonce bump + authorization processing)
  • test/state/host.cpp (prepare_message() nonce-max check at depth 0)

Expected behavior

Top-level tx execution should not be skipped in this valid case; geth executes and mutates storage.
Only transactions with invalid tx nonce per EIP-2681 should be rejected at validation boundary.

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