Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
530 changes: 530 additions & 0 deletions .claude/commands/enhance-ported-test.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ When reviewing PRs that implement or test EIPs:
## When to Use Skills

- Writing or modifying tests → run `/write-test` first
- Cleaning up or future-proofing a `tests/ported_static/` test → run `/enhance-ported-test` first
- Writing or modifying pytester-based plugin tests → run `/pytester` first
- Filling test fixtures → run `/fill-tests` first
- Implementing an EIP or modifying fork code in `src/` → run `/implement-eip` first
Expand All @@ -55,6 +56,7 @@ When reviewing PRs that implement or test EIPs:
## Available Skills

- `/write-test` — test writing patterns, fixtures, markers, bytecode helpers
- `/enhance-ported-test` — ordered methodology to clean up & future-proof `tests/ported_static/` tests
- `/pytester` — pytester execution modes, isolation, output handling for plugin tests
- `/fill-tests` — `fill` CLI reference, flags, debugging, benchmark tests
- `/implement-eip` — fork structure, import rules, adding opcodes/precompiles/tx types
Expand Down
127 changes: 6 additions & 121 deletions tests/ported_static/amsterdam_skip_list.txt

Large diffs are not rendered by default.

103 changes: 27 additions & 76 deletions tests/ported_static/stArgsZeroOneBalance/test_add_non_const.py
Original file line number Diff line number Diff line change
@@ -1,116 +1,67 @@
"""
Test_add_non_const.
Verify ADD over non-constant operands: the contract adds its own balance to
itself, where that balance equals the value sent by the transaction.

Ported from:
state_tests/stArgsZeroOneBalance/addNonConstFiller.yml

@manually-enhanced: Do not overwrite. Parametrized on the transaction value
(the real discriminator), the self-referential balance reads use
`BALANCE(ADDRESS)` instead of a hardcoded address, and the post asserts the
`2 * tx_value` result directly; env/gas boilerplate removed. A canary slot
keeps the `tx_value=0` arm observable (its result slot stays zero).
"""

import pytest
from execution_testing import (
Account,
Address,
Alloc,
Bytes,
Environment,
Fork,
StateTestFiller,
Transaction,
)
from execution_testing.forks import Fork
from execution_testing.specs.static_state.expect_section import (
resolve_expect_post,
)
from execution_testing.vm import Op

REFERENCE_SPEC_GIT_PATH = "N/A"
REFERENCE_SPEC_VERSION = "N/A"

CANARY = 0xC0DE


@pytest.mark.ported_from(
["state_tests/stArgsZeroOneBalance/addNonConstFiller.yml"],
)
@pytest.mark.valid_from("Cancun")
@pytest.mark.parametrize(
"d, g, v",
[
pytest.param(
0,
0,
0,
id="-v0",
),
pytest.param(
0,
0,
1,
id="-v1",
),
],
)
@pytest.mark.pre_alloc_mutable
@pytest.mark.valid_from("Frontier")
@pytest.mark.parametrize("tx_value", [0, 1])
def test_add_non_const(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
d: int,
g: int,
v: int,
tx_value: int,
) -> None:
"""Test_add_non_const."""
coinbase = Address(0x2ADC25665018AA1FE0E6BC666DAC8FC2697FF9BA)
sender = pre.fund_eoa(amount=0xDE0B6B3A7640000)
"""Add the contract's own balance to itself and store the result."""
sender = pre.fund_eoa()

env = Environment(
fee_recipient=coinbase,
number=1,
timestamp=1000,
prev_randao=0x20000,
base_fee_per_gas=10,
gas_limit=1000000,
)

# Source: lll
# { [[ 0 ]](ADD (BALANCE <contract:target:0x095e7baea6a6c7c4c2dfeb977efac326af552d87>) (BALANCE <contract:target:0x095e7baea6a6c7c4c2dfeb977efac326af552d87>)) } # noqa: E501
target = pre.deploy_contract( # noqa: F841
# ADD with non-constant operands: the contract's own balance added to
# itself. The balance equals the value sent by the transaction. The
# canary proves the code ran even when the stored result is zero.
target = pre.deploy_contract(
code=Op.SSTORE(
key=0x0,
value=Op.ADD(
Op.BALANCE(address=0xF1722FE346FA35E045DE07E47CF6AF9BAE8ADE0A),
Op.BALANCE(address=0xF1722FE346FA35E045DE07E47CF6AF9BAE8ADE0A),
),
value=Op.ADD(Op.BALANCE(Op.ADDRESS), Op.BALANCE(Op.ADDRESS)),
)
+ Op.SSTORE(key=0x1, value=CANARY)
+ Op.STOP,
nonce=0,
address=Address(0xF1722FE346FA35E045DE07E47CF6AF9BAE8ADE0A), # noqa: E501
)

expect_entries_: list[dict] = [
{
"indexes": {"data": -1, "gas": -1, "value": 0},
"network": [">=Cancun"],
"result": {target: Account(storage={0: 0})},
},
{
"indexes": {"data": -1, "gas": -1, "value": 1},
"network": [">=Cancun"],
"result": {target: Account(storage={0: 2})},
},
]

post, _exc = resolve_expect_post(expect_entries_, d, g, v, fork)

tx_data = [
Bytes(""),
]
tx_gas = [400000]
tx_value = [0, 1]
# ADD(BALANCE, BALANCE) over a balance equal to the sent value.
post = {target: Account(storage={0: 2 * tx_value, 1: CANARY})}

tx = Transaction(
sender=sender,
to=target,
data=tx_data[d],
gas_limit=tx_gas[g],
value=tx_value[v],
error=_exc,
value=tx_value,
protected=fork.supports_protected_txs(),
)

state_test(env=env, pre=pre, post=post, tx=tx)
state_test(pre=pre, post=post, tx=tx)
88 changes: 48 additions & 40 deletions tests/ported_static/stCreateTest/test_create_empty_contract.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
"""
Test_create_empty_contract.
Test CREATE of an empty contract and measure the CREATE gas cost.

Ported from:
state_tests/stCreateTest/CREATE_EmptyContractFiller.json
state_tests/stCreateTest/CREATE_EmptyContractWithBalanceFiller.json

@manually-enhanced: Do not overwrite. CREATE gas via CodeGasMeasure; dynamic
address + fork-derived cost; empty/with-balance folded into one parametrize.
"""

import pytest
from execution_testing import (
Account,
Address,
Alloc,
Bytes,
Environment,
CodeGasMeasure,
Fork,
StateTestFiller,
Transaction,
compute_create_address,
Expand All @@ -21,56 +24,61 @@
REFERENCE_SPEC_GIT_PATH = "N/A"
REFERENCE_SPEC_VERSION = "N/A"

GAS_SLOT = 0x64


@pytest.mark.ported_from(
["state_tests/stCreateTest/CREATE_EmptyContractFiller.json"],
[
"state_tests/stCreateTest/CREATE_EmptyContractFiller.json",
"state_tests/stCreateTest/CREATE_EmptyContractWithBalanceFiller.json",
],
)
@pytest.mark.valid_from("SpuriousDragon")
@pytest.mark.parametrize(
"create_value",
[
pytest.param(0, id="empty_contract"),
pytest.param(1, id="with_balance"),
],
)
@pytest.mark.valid_from("Cancun")
@pytest.mark.pre_alloc_mutable
def test_create_empty_contract(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
create_value: int,
) -> None:
"""Test_create_empty_contract."""
coinbase = Address(0x2ADC25665018AA1FE0E6BC666DAC8FC2697FF9BA)
contract_0 = Address(0xB94F5374FCE5EDBC8E2A8697C15331677E6EBF0B)
sender = pre.fund_eoa(amount=0xE8D4A51000)

env = Environment(
fee_recipient=coinbase,
number=1,
timestamp=1000,
prev_randao=0x20000,
base_fee_per_gas=10,
gas_limit=10000000,
"""CREATE an empty contract (empty init code) and measure its gas."""
# CREATE with size=0x20 over never-written memory runs 32 zero bytes as
# init code (STOP on the first byte), depositing no code -> an empty
# account with nonce 1 (and the transferred value as balance).
create_code = Op.CREATE(
value=create_value,
offset=0x0,
size=0x20,
new_memory_size=0x20,
init_code_size=0x20,
)

# Source: lll
# { [[0]](GAS) [[1]] (CREATE 0 0 32) [[100]] (GAS) }
contract_0 = pre.deploy_contract( # noqa: F841
code=Op.SSTORE(key=0x0, value=Op.GAS)
+ Op.SSTORE(key=0x1, value=Op.CREATE(value=0x0, offset=0x0, size=0x20))
+ Op.SSTORE(key=0x64, value=Op.GAS)
+ Op.STOP,
nonce=0,
contract = pre.deploy_contract(
code=CodeGasMeasure(
code=create_code,
extra_stack_items=1,
sstore_key=GAS_SLOT,
),
balance=create_value,
)

tx = Transaction(
sender=sender,
to=contract_0,
data=Bytes(""),
gas_limit=600000,
sender=pre.fund_eoa(),
to=contract,
state_gas_reservoir=0,
)

created = compute_create_address(address=contract, nonce=1)
post = {
compute_create_address(address=contract_0, nonce=0): Account(nonce=1),
contract_0: Account(
storage={
0: 0x8D5B6,
1: compute_create_address(address=contract_0, nonce=0),
100: 0x7ABF8,
},
contract: Account(
storage={GAS_SLOT: create_code.gas_cost(fork)}, balance=0
),
created: Account(nonce=1, balance=create_value),
}

state_test(env=env, pre=pre, post=post, tx=tx)
state_test(pre=pre, post=post, tx=tx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""
Test CREATE of an empty contract followed by a CALL to it, measuring the
CALL gas cost.

Ported from:
state_tests/stCreateTest/CREATE_EmptyContractAndCallIt_0weiFiller.json
state_tests/stCreateTest/CREATE_EmptyContractAndCallIt_1weiFiller.json

@manually-enhanced: Do not overwrite. CALL gas via CodeGasMeasure; dynamic
address (runtime SLOAD); 0wei/1wei folded into one parametrize.
"""

import pytest
from execution_testing import (
Account,
Alloc,
CodeGasMeasure,
Fork,
StateTestFiller,
Transaction,
compute_create_address,
)
from execution_testing.vm import Op

REFERENCE_SPEC_GIT_PATH = "N/A"
REFERENCE_SPEC_VERSION = "N/A"

ADDRESS_SLOT = 0x1
GAS_SLOT = 0x64

FORWARDED_GAS = 0xEA60


@pytest.mark.ported_from(
[
"state_tests/stCreateTest/CREATE_EmptyContractAndCallIt_0weiFiller.json", # noqa: E501
"state_tests/stCreateTest/CREATE_EmptyContractAndCallIt_1weiFiller.json", # noqa: E501
],
)
@pytest.mark.valid_from("Berlin")
@pytest.mark.parametrize(
"call_value",
[
pytest.param(0, id="0wei"),
pytest.param(1, id="1wei"),
],
)
def test_create_empty_contract_and_call_it(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
call_value: int,
) -> None:
"""CREATE an empty contract, then CALL it and measure the CALL gas."""
# CREATE over never-written memory deposits no code -> an empty account
# with nonce 1. Its address is stored so the CALL can target it at
# runtime (it is not known when the caller code is assembled).
create_code = Op.CREATE(
value=0x0,
offset=0x0,
size=0x20,
new_memory_size=0x20,
init_code_size=0x20,
)
# The created account already exists (CREATE set its nonce) and is warm
# (CREATE accessed it), so the CALL is a warm call to an existing account.
call_code = Op.CALL(
gas=FORWARDED_GAS,
address=Op.SLOAD(key=ADDRESS_SLOT, key_warm=True),
value=call_value,
args_offset=0x0,
args_size=0x0,
ret_offset=0x0,
ret_size=0x0,
address_warm=True,
value_transfer=call_value > 0,
account_new=False,
)
contract = pre.deploy_contract(
code=Op.SSTORE(key=ADDRESS_SLOT, value=create_code)
+ CodeGasMeasure(
code=call_code,
extra_stack_items=1,
sstore_key=GAS_SLOT,
),
balance=call_value,
)

tx = Transaction(
sender=pre.fund_eoa(),
to=contract,
state_gas_reservoir=0,
)

# A value-bearing CALL whose empty callee consumes nothing measures
# gas_cost minus the stipend (forwarded then returned unused).
stipend = fork.gas_costs().CALL_STIPEND if call_value else 0
created = compute_create_address(address=contract, nonce=1)
post = {
contract: Account(
storage={
ADDRESS_SLOT: created,
GAS_SLOT: call_code.gas_cost(fork) - stipend,
},
balance=0,
),
# The transferred value on the 1wei case proves the CALL executed.
created: Account(nonce=1, balance=call_value),
}

state_test(pre=pre, post=post, tx=tx)
Loading
Loading