Skip to content

Commit 0e2bac8

Browse files
authored
feat(tests): update 7702 precompile test cases (#1431)
- Add a test case that calls the delegated precompile acct directly from the same transaction as the auth. Supply enough gas only to cover the intrinsic cost of the call, with no extra gas for any precompile code execution. - Update the test case for all call opcodes to use all of the call opcodes.
1 parent eaad0dd commit 0e2bac8

File tree

2 files changed

+57
-9
lines changed

2 files changed

+57
-9
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Test fixtures for use by clients are available for each release on the [Github r
1919

2020
### 🧪 Test Cases
2121

22+
- ✨ Test 7702 precompile case in same transaction as delegation without extra gas in case of precompile code execution; parametrize all call opcodes in existing precompile test ([#1431](https://github.com/ethereum/execution-spec-tests/pull/1431)).
23+
2224
## [v4.2.0](https://github.com/ethereum/execution-spec-tests/releases/tag/v4.2.0) - 2025-04-08
2325

2426
**Note**: Although not a breaking change, `consume` users should delete the cache directory (typically located at `~/.cache/ethereum-execution-spec-tests`) used to store downloaded fixture release tarballs. This release adds support for [ethereum/tests](https://github.com/ethereum/tests) and [ethereum/legacytests](https://github.com/ethereum/legacytests) fixture release downloads and the structure of the cache directory has been updated to accommodate this change.

tests/prague/eip7702_set_code_tx/test_set_code_txs.py

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from ethereum_test_tools import Macros as Om
4040
from ethereum_test_tools import Opcodes as Op
4141
from ethereum_test_tools.eof.v1 import Container, Section
42+
from ethereum_test_types import TransactionReceipt
4243

4344
from ...cancun.eip4844_blobs.spec import Spec as Spec4844
4445
from ..eip6110_deposits.helpers import DepositRequest
@@ -2514,32 +2515,31 @@ def test_set_code_to_log(
25142515
)
25152516

25162517

2517-
@pytest.mark.with_all_call_opcodes(
2518-
selector=(
2519-
lambda opcode: opcode
2520-
not in [Op.STATICCALL, Op.CALLCODE, Op.DELEGATECALL, Op.EXTDELEGATECALL, Op.EXTSTATICCALL]
2521-
)
2522-
)
2518+
@pytest.mark.with_all_call_opcodes
25232519
@pytest.mark.with_all_precompiles
25242520
def test_set_code_to_precompile(
25252521
state_test: StateTestFiller,
25262522
pre: Alloc,
25272523
precompile: int,
25282524
call_opcode: Op,
25292525
):
2530-
"""Test setting the code of an account to a pre-compile address."""
2526+
"""
2527+
Test setting the code of an account to a pre-compile address and executing all call
2528+
opcodes.
2529+
"""
25312530
auth_signer = pre.fund_eoa(auth_account_start_balance)
25322531

2532+
value = 1 if call_opcode in {Op.CALL, Op.CALLCODE, Op.EXTCALL} else 0
25332533
caller_code_storage = Storage()
25342534
caller_code = (
25352535
Op.SSTORE(
25362536
caller_code_storage.store_next(call_return_code(opcode=call_opcode, success=True)),
2537-
call_opcode(address=auth_signer),
2537+
call_opcode(address=auth_signer, value=value, gas=0),
25382538
)
25392539
+ Op.SSTORE(caller_code_storage.store_next(0), Op.RETURNDATASIZE)
25402540
+ Op.STOP
25412541
)
2542-
caller_code_address = pre.deploy_contract(caller_code)
2542+
caller_code_address = pre.deploy_contract(caller_code, balance=value)
25432543

25442544
tx = Transaction(
25452545
sender=pre.fund_eoa(),
@@ -2570,6 +2570,52 @@ def test_set_code_to_precompile(
25702570
)
25712571

25722572

2573+
@pytest.mark.with_all_precompiles
2574+
def test_set_code_to_precompile_not_enough_gas_for_precompile_execution(
2575+
state_test: StateTestFiller,
2576+
pre: Alloc,
2577+
fork: Fork,
2578+
precompile: int,
2579+
):
2580+
"""
2581+
Test set code to precompile and making direct call in same transaction with intrinsic gas
2582+
only, no extra gas for precompile execution.
2583+
"""
2584+
auth_signer = pre.fund_eoa(amount=1)
2585+
auth = AuthorizationTuple(address=Address(precompile), nonce=0, signer=auth_signer)
2586+
2587+
intrinsic_gas = fork.transaction_intrinsic_cost_calculator()(
2588+
authorization_list_or_count=[auth],
2589+
)
2590+
discount = min(
2591+
Spec.PER_EMPTY_ACCOUNT_COST - Spec.PER_AUTH_BASE_COST,
2592+
intrinsic_gas // 5, # max discount EIP-3529
2593+
)
2594+
2595+
tx = Transaction(
2596+
sender=pre.fund_eoa(),
2597+
to=auth_signer,
2598+
gas_limit=intrinsic_gas,
2599+
value=1,
2600+
authorization_list=[auth],
2601+
# explicitly check expected gas, no precompile code executed
2602+
expected_receipt=TransactionReceipt(gas_used=intrinsic_gas - discount),
2603+
)
2604+
2605+
state_test(
2606+
pre=pre,
2607+
tx=tx,
2608+
post={
2609+
auth_signer: Account(
2610+
# implicitly checks no OOG, successful tx transfers ``value=1``
2611+
balance=2,
2612+
code=Spec.delegation_designation(Address(precompile)),
2613+
nonce=1,
2614+
),
2615+
},
2616+
)
2617+
2618+
25732619
def deposit_contract_initial_storage() -> Storage:
25742620
"""Return the initial storage of the deposit contract."""
25752621
storage = Storage()

0 commit comments

Comments
 (0)