Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
general/code_coverage/test_coverage = Measured on 2026-09-10 with #3524 (e330e06f60) rebased onto forks/amsterdam (c998b45fe8): 4936/4944 test statements and 452/462 branches covered by 2116 passing fixture variants. The eight missed statements are six defensive invalid-parameter raises and two lines adapting SSTORE counts to future gas repricing. Reproduce with --cov=tests/amsterdam/eip8037_state_creation_gas_cost_increase --cov-branch; see #3524 for scope and validation limits.
general/code_coverage/eels = Measured on 2026-09-21 at forks/amsterdam c335bc4e9e with `uv run fill --fork=Amsterdam --cov=ethereum.forks.amsterdam --cov-branch tests/amsterdam/eip8037_state_creation_gas_cost_increase` (2179 fixtures through the in-process t8n). Every EIP-8037 line is executed: vm/__init__.py 67/67 statements, vm/gas.py 338/351, vm/interpreter.py 146/149, vm/instructions/system.py 278/293, vm/instructions/storage.py 66/67, transactions.py 256/292 and fork.py 192/298, where every miss is pre-existing code classified under missed_lines. The one EIP-8037 path this directory does not reach, the top-frame NEW_ACCOUNT charge for a value transfer to a non-alive recipient (charge_value_transfer_to_non_alive_account), is exercised by tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/test_top_frame_charges.py::test_top_frame_new_account_charged_as_state_gas.
general/code_coverage/missed_lines = All misses in the files EIP-8037 touches are pre-existing branches: the static-context and delegated-code arms of CALL, CALLCODE, DELEGATECALL, STATICCALL, SELFDESTRUCT and TSTORE; EIP-7702 warm delegation access, authority recovery and authorization validation errors; transaction decoding, signature recovery and validity errors (nonce overflow, priority fee above max fee, blob count and versioned-hash checks, chain id, insufficient balance, non-EOA sender, missing system contract code); the memory-expansion overflow and gas_left shortfall branches of vm/gas.py together with excess-blob-gas arithmetic and the blob-gas capacity check; and block-level functions the t8n never runs (state_transition, execute_block, apply_body, validate_header, check_gas_limit, get_last_256_block_hashes, process_general_purpose_requests, process_withdrawals). The two-dimensional admission checks in check_block_gas_capacity and the gas split and accounting in check_transaction and process_transaction are fully executed.
Original file line number Diff line number Diff line change
Expand Up @@ -2284,14 +2284,15 @@ def test_create_collision_refunds_state_gas(
create_opcode: Op,
) -> None:
"""
Verify CREATE/CREATE2 address collision refunds account state gas.
Verify a CREATE/CREATE2 address collision leaves the reservoir intact.

The collision path increments the factory nonce and burns the
forwarded execution gas (consumed by the never-spawned child), but
still refunds `GAS_NEW_ACCOUNT` to the reservoir. Tight gas
tuning limits the factory's post-collision `gas_left` so the
probe SSTORE can only succeed via the refunded reservoir, not
by spilling state gas from `gas_left`.
The collision target has code, so it is alive and no
`GAS_NEW_ACCOUNT` charge is made for it. The collision path
increments the factory nonce and burns the forwarded execution gas
(consumed by the never-spawned child) while the reservoir returns
untouched. Tight gas tuning limits the factory's post-collision
`gas_left` so the probe SSTORE can only succeed via the intact
reservoir, not by spilling state gas from `gas_left`.
"""
sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)

Expand Down Expand Up @@ -3610,3 +3611,110 @@ def test_no_account_charge_on_existing_account(
),
}
state_test(pre=pre, post=post, tx=tx)


@pytest.mark.with_all_create_opcodes()
@pytest.mark.parametrize(
("failure_op", "halts"),
[
pytest.param(Op.REVERT(0, 0), False, id="revert"),
pytest.param(Op.INVALID, True, id="halt"),
],
)
@pytest.mark.parametrize(
"reservoir_covers",
[
pytest.param(False, id="no_reservoir"),
pytest.param(True, id="reservoir_covers"),
],
)
@pytest.mark.valid_from("EIP8037")
def test_failed_create_on_existing_account_refills_nothing(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
create_opcode: Op,
failure_op: Bytecode,
halts: bool,
reservoir_covers: bool,
) -> None:
"""
Verify a create frame failing on an alive destination refills nothing.

The pre-funded target is never charged NEW_ACCOUNT, so the child
failure has no charge to return. The factory's gas is tuned so its
probe SSTORE only fits when the reservoir funds the state gas: a
phantom refill would let the `no_reservoir` arms succeed.
"""
sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)

init_code = failure_op
mstore_value, size = init_code_at_high_bytes(init_code)
salt = 0
create_call = (
create_opcode(
value=0,
offset=0,
size=size,
salt=salt,
init_code_size=size,
account_new=False,
)
if create_opcode == Op.CREATE2
else create_opcode(
value=0,
offset=0,
size=size,
init_code_size=size,
account_new=False,
)
)

probe_slot = 0
setup_code = Op.MSTORE(0, mstore_value) + Op.POP(create_call)
factory_code = setup_code + Op.SSTORE(probe_slot, 1)
factory = pre.deploy_contract(code=factory_code)

target = compute_create_address(
address=factory,
nonce=1,
salt=salt,
initcode=bytes(init_code),
opcode=create_opcode,
)
pre.fund_address(target, amount=1)

# Leave the factory a window where the probe's execution fits but
# spilling its state gas from `gas_left` does not.
probe_execution = Op.SSTORE(probe_slot, 1).execution_cost(fork)
retained = probe_execution + sstore_state_gas // 2
if halts:
# The halt burns the child's grant; the withheld 1/64 remains.
remaining = retained * 64
else:
# The revert returns the grant less what the init code spent.
remaining = retained + init_code.execution_cost(fork)
forwarded_gas = remaining + setup_code.execution_cost(fork)

caller_storage = Storage()
caller = pre.deploy_contract(
code=Op.SSTORE(
caller_storage.store_next(reservoir_covers, "factory_succeeds"),
Op.CALL(gas=forwarded_gas, address=factory),
)
)

tx = Transaction(
to=caller,
state_gas_reservoir=sstore_state_gas if reservoir_covers else 0,
sender=pre.fund_eoa(),
)

post = {
caller: Account(storage=caller_storage),
factory: Account(nonce=2, storage={probe_slot: 1})
if reservoir_covers
else Account(nonce=1, storage={}),
target: Account(nonce=0, balance=1, code=b""),
}
state_test(pre=pre, post=post, tx=tx)
Loading