Skip to content

Commit c0a381c

Browse files
authored
fix(tests): Fix Existing EOF + EIP-7702 Tests (#821)
* fix(tools): Conditional EOF generator * fix(tests): EOF + EIP-7702 tests * docs: changelog * Update docs/CHANGELOG.md
1 parent 12c0087 commit c0a381c

File tree

3 files changed

+105
-18
lines changed

3 files changed

+105
-18
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Test fixtures for use by clients are available for each release on the [Github r
1212
- ✨ Example test `tests/frontier/opcodes/test_dup.py` now includes EOF parametrization ([#610](https://github.com/ethereum/execution-spec-tests/pull/610)).
1313
- ✨ Convert all opcodes validation test `tests/frontier/opcodes/test_all_opcodes.py` ([#748](https://github.com/ethereum/execution-spec-tests/pull/748)).
1414
- ✨ Update [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) tests for Devnet-3 ([#733](https://github.com/ethereum/execution-spec-tests/pull/733))
15+
- 🐞 Fix [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702)+EOF tests due to incorrect test expectations and faulty `Conditional` test generator in EOF mode ([#821](https://github.com/ethereum/execution-spec-tests/pull/821))
1516

1617
### 🛠️ Framework
1718

@@ -38,6 +39,7 @@ Test fixtures for use by clients are available for each release on the [Github r
3839
- ✨ Added `selector` and `marks` fields to all `@pytest.mark.with_all*` markers, which allows passing lambda functions to select or mark specific parametrized values (see [documentation](https://ethereum.github.io/execution-spec-tests/main/writing_tests/test_markers/#covariant-marker-keyword-arguments) for more information) ([#762](https://github.com/ethereum/execution-spec-tests/pull/762)).
3940
- ✨ Improves consume input flags for develop and stable fixture releases, fixes `--help` flag for consume ([#745](https://github.com/ethereum/execution-spec-tests/pull/745)).
4041
- 🐞 Fix erroneous fork message in pytest session header with development forks ([#806](https://github.com/ethereum/execution-spec-tests/pull/806)).
42+
- 🐞 Fix `Conditional` code generator in EOF mode ([#821](https://github.com/ethereum/execution-spec-tests/pull/821))
4143

4244
### 🔧 EVM Tools
4345

src/ethereum_test_tools/code/generators.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,17 @@ def __new__(
217217
# Then we need to do the conditional jump by skipping the false branch
218218
condition = Op.JUMPI(Op.ADD(Op.PC, len(if_false) + 3), condition)
219219

220+
# Finally we append the condition, false and true branches, plus the jumpdest at the
221+
# very end
222+
bytecode = condition + if_false + if_true + Op.JUMPDEST
223+
220224
elif evm_code_type == EVMCodeType.EOF_V1:
221-
if_false += Op.RJUMP[len(if_true)]
225+
if not if_false.terminating:
226+
if_false += Op.RJUMP[len(if_true)]
222227
condition = Op.RJUMPI[len(if_false)](condition)
223228

224-
# Finally we append the true and false branches, and the condition, plus the jumpdest at
225-
# the very end
226-
bytecode = condition + if_false + if_true + Op.JUMPDEST
229+
# Finally we append the condition, false and true branches
230+
bytecode = condition + if_false + if_true
227231

228232
return super().__new__(cls, bytecode)
229233

tests/prague/eip7702_set_code_tx/test_set_code_txs.py

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ def test_tx_into_self_delegating_set_code(
792792
pre: Alloc,
793793
):
794794
"""
795-
Test a transaction that has entry-point into a set-code address that delegates to itself.
795+
Test a transaction that has entry-point into a set-code account that delegates to itself.
796796
"""
797797
auth_signer = pre.fund_eoa(auth_account_start_balance)
798798

@@ -828,7 +828,8 @@ def test_tx_into_chain_delegating_set_code(
828828
pre: Alloc,
829829
):
830830
"""
831-
Test a transaction that has entry-point into a set-code address that delegates to itself.
831+
Test a transaction that has entry-point into a set-code account that delegates to another
832+
set-code account.
832833
"""
833834
auth_signer_1 = pre.fund_eoa(auth_account_start_balance)
834835
auth_signer_2 = pre.fund_eoa(auth_account_start_balance)
@@ -870,14 +871,20 @@ def test_call_into_self_delegating_set_code(
870871
call_opcode: Op,
871872
):
872873
"""
873-
Test a transaction that has entry-point into a set-code address that delegates to itself.
874+
Test call into a set-code account that delegates to itself.
874875
"""
875876
auth_signer = pre.fund_eoa(auth_account_start_balance)
876877

877878
storage = Storage()
878879
entry_code = (
879880
Op.SSTORE(
880-
storage.store_next(call_return_code(opcode=call_opcode, success=False)),
881+
storage.store_next(
882+
call_return_code(
883+
opcode=call_opcode,
884+
success=False,
885+
revert=(call_opcode == Op.EXTDELEGATECALL),
886+
)
887+
),
881888
call_opcode(address=auth_signer),
882889
)
883890
+ Op.STOP
@@ -916,15 +923,21 @@ def test_call_into_chain_delegating_set_code(
916923
call_opcode: Op,
917924
):
918925
"""
919-
Test a transaction that has entry-point into a set-code address that delegates to itself.
926+
Test call into a set-code account that delegates to another set-code account.
920927
"""
921928
auth_signer_1 = pre.fund_eoa(auth_account_start_balance)
922929
auth_signer_2 = pre.fund_eoa(auth_account_start_balance)
923930

924931
storage = Storage()
925932
entry_code = (
926933
Op.SSTORE(
927-
storage.store_next(call_return_code(opcode=call_opcode, success=False)),
934+
storage.store_next(
935+
call_return_code(
936+
opcode=call_opcode,
937+
success=False,
938+
revert=(call_opcode == Op.EXTDELEGATECALL),
939+
)
940+
),
928941
call_opcode(address=auth_signer_1),
929942
)
930943
+ Op.STOP
@@ -1117,12 +1130,7 @@ def test_ext_code_on_self_set_code(
11171130
)
11181131

11191132

1120-
@pytest.mark.with_all_call_opcodes(
1121-
selector=(
1122-
lambda opcode: opcode
1123-
not in [Op.STATICCALL, Op.CALLCODE, Op.DELEGATECALL, Op.EXTDELEGATECALL, Op.EXTSTATICCALL]
1124-
)
1125-
)
1133+
@pytest.mark.with_all_evm_code_types()
11261134
@pytest.mark.parametrize(
11271135
"set_code_address_first",
11281136
[
@@ -1133,7 +1141,6 @@ def test_ext_code_on_self_set_code(
11331141
def test_set_code_address_and_authority_warm_state(
11341142
state_test: StateTestFiller,
11351143
pre: Alloc,
1136-
call_opcode: Op,
11371144
set_code_address_first: bool,
11381145
):
11391146
"""
@@ -1150,6 +1157,7 @@ def test_set_code_address_and_authority_warm_state(
11501157
set_code = Op.STOP
11511158
set_code_to_address = pre.deploy_contract(set_code)
11521159

1160+
call_opcode = Op.CALL
11531161
overhead_cost = 3 * len(call_opcode.kwargs) # type: ignore
11541162
if call_opcode == Op.CALL:
11551163
overhead_cost -= 1 # GAS opcode is less expensive than a PUSH
@@ -1176,7 +1184,7 @@ def test_set_code_address_and_authority_warm_state(
11761184
callee_code += code_gas_measure_authority + code_gas_measure_set_code
11771185
callee_code += Op.SSTORE(slot_call_success, 1) + Op.STOP
11781186

1179-
callee_address = pre.deploy_contract(callee_code)
1187+
callee_address = pre.deploy_contract(callee_code, evm_code_type=EVMCodeType.LEGACY)
11801188
callee_storage = Storage()
11811189
callee_storage[slot_call_success] = 1
11821190
callee_storage[slot_set_code_to_warm_state] = 2_600 if set_code_address_first else 100
@@ -1210,6 +1218,79 @@ def test_set_code_address_and_authority_warm_state(
12101218
)
12111219

12121220

1221+
@pytest.mark.with_all_call_opcodes()
1222+
@pytest.mark.parametrize(
1223+
"set_code_address_first",
1224+
[
1225+
pytest.param(True, id="call_set_code_address_first_then_authority"),
1226+
pytest.param(False, id="call_authority_first_then_set_code_address"),
1227+
],
1228+
)
1229+
def test_set_code_address_and_authority_warm_state_call_types(
1230+
state_test: StateTestFiller,
1231+
pre: Alloc,
1232+
call_opcode: Op,
1233+
set_code_address_first: bool,
1234+
):
1235+
"""
1236+
Test set to code address and authority warm status after a call to
1237+
authority address, or viceversa, using all available call opcodes
1238+
without using `GAS` opcode (unavailable in EOF).
1239+
"""
1240+
auth_signer = pre.fund_eoa(auth_account_start_balance)
1241+
1242+
slot = count(1)
1243+
slot_call_return_code = next(slot)
1244+
slot_call_success = next(slot)
1245+
1246+
set_code = Op.STOP
1247+
set_code_to_address = pre.deploy_contract(set_code)
1248+
1249+
call_set_code_to_address = Op.SSTORE(
1250+
slot_call_return_code, call_opcode(address=set_code_to_address)
1251+
)
1252+
call_authority_address = Op.SSTORE(slot_call_return_code, call_opcode(address=auth_signer))
1253+
1254+
callee_code = Bytecode()
1255+
if set_code_address_first:
1256+
callee_code += call_set_code_to_address + call_authority_address
1257+
else:
1258+
callee_code += call_authority_address + call_set_code_to_address
1259+
callee_code += Op.SSTORE(slot_call_success, 1) + Op.STOP
1260+
1261+
callee_address = pre.deploy_contract(callee_code)
1262+
callee_storage = Storage()
1263+
callee_storage[slot_call_return_code] = call_return_code(opcode=call_opcode, success=True)
1264+
callee_storage[slot_call_success] = 1
1265+
1266+
tx = Transaction(
1267+
gas_limit=1_000_000,
1268+
to=callee_address,
1269+
authorization_list=[
1270+
AuthorizationTuple(
1271+
address=set_code_to_address,
1272+
nonce=0,
1273+
signer=auth_signer,
1274+
),
1275+
],
1276+
sender=pre.fund_eoa(),
1277+
)
1278+
1279+
state_test(
1280+
env=Environment(),
1281+
pre=pre,
1282+
tx=tx,
1283+
post={
1284+
callee_address: Account(storage=callee_storage),
1285+
auth_signer: Account(
1286+
nonce=1,
1287+
code=Spec.delegation_designation(set_code_to_address),
1288+
balance=auth_account_start_balance,
1289+
),
1290+
},
1291+
)
1292+
1293+
12131294
@pytest.mark.parametrize(
12141295
"balance",
12151296
[0, 1],

0 commit comments

Comments
 (0)