Skip to content

t8n: sender/signature mismatch is accepted (JSON sender trusted over v/r/s) #1482

@chfast

Description

@chfast

Summary

evmone-t8n accepts transactions based on the JSON sender field without validating that (v,r,s) recovers to the same sender.

This creates a cross-client divergence with geth evm t8n: a tx signed by account A can be executed as account B in evmone-t8n if JSON sets sender=B.

Why this matters

In t8n/state-transition semantics, sender should be derived from signature and chain rules (or at least validated against provided sender).
Current behavior lets malformed tx JSON produce wrong state roots and acceptance/rejection results.

Reproducer

alloc.json

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

env.json

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

txs.json

v,r,s below are from a tx signed by 0xa94f5374... (not by 0x1111...).

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

Commands

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

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

Observed

  • evmone-t8n:
    • rejected: []
    • gasUsed: 0x5208
    • executes transaction and updates state.
  • geth evm t8n:
    • rejects tx:
      • insufficient funds ... address 0xa94f5374... have 0 want 21000
    • gasUsed: 0x0
    • no executed tx in block result.

Suspected root cause

sender is loaded from JSON and used directly for state checks/execution:

  • test/utils/statetest_loader.cpp
    • o.sender = load_if_exists<evmc::address>(j, "sender");
    • parses v/r/s but does not recover/validate sender from signature.
  • test/state/state.cpp
    • validation and balance checks use tx.sender directly.

So (v,r,s) authenticity is effectively not enforced for tx sender in evmone-t8n.

Suggested fix direction

Recover sender from signature (per tx type / chain id / fork rules) and either:

  1. Use recovered sender as authoritative, or
  2. Reject when provided sender disagrees with recovered sender.

Also reject malformed signatures consistently with other clients.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions