Skip to content

Commit 71046f9

Browse files
committed
refactor(tests-ported): Condense stTimeConsuming to a single file
1 parent 4f8c69e commit 71046f9

13 files changed

+251
-1638
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
"""
2+
SSTORE combination tests for all initial storage states.
3+
4+
Exercises every combination of call types across four call slots,
5+
varying the update-contract's initial storage state (0, 1, or 2).
6+
7+
Ported from all ``sstore_combinations_initial*_ParisFiller.json``
8+
in ``state_tests/stTimeConsuming/``.
9+
"""
10+
11+
from enum import StrEnum
12+
13+
import pytest
14+
from execution_testing import (
15+
Account,
16+
Alloc,
17+
Bytecode,
18+
StateTestFiller,
19+
Transaction,
20+
compute_create_address,
21+
)
22+
from execution_testing.forks import Fork
23+
from execution_testing.vm import Op
24+
25+
REFERENCE_SPEC_GIT_PATH = "N/A"
26+
REFERENCE_SPEC_VERSION = "N/A"
27+
28+
pytestmark = [
29+
pytest.mark.ported_from(
30+
"state_tests/stTimeConsuming/sstore_combinations_initial00_ParisFiller.json",
31+
"state_tests/stTimeConsuming/sstore_combinations_initial00_2_ParisFiller.json",
32+
"state_tests/stTimeConsuming/sstore_combinations_initial01_ParisFiller.json",
33+
"state_tests/stTimeConsuming/sstore_combinations_initial01_2_ParisFiller.json",
34+
"state_tests/stTimeConsuming/sstore_combinations_initial10_ParisFiller.json",
35+
"state_tests/stTimeConsuming/sstore_combinations_initial10_2_ParisFiller.json",
36+
"state_tests/stTimeConsuming/sstore_combinations_initial11_ParisFiller.json",
37+
"state_tests/stTimeConsuming/sstore_combinations_initial11_2_ParisFiller.json",
38+
"state_tests/stTimeConsuming/sstore_combinations_initial20_ParisFiller.json",
39+
"state_tests/stTimeConsuming/sstore_combinations_initial20_2_ParisFiller.json",
40+
"state_tests/stTimeConsuming/sstore_combinations_initial21_ParisFiller.json",
41+
"state_tests/stTimeConsuming/sstore_combinations_initial21_2_ParisFiller.json",
42+
),
43+
pytest.mark.valid_from("Byzantium"),
44+
pytest.mark.slow,
45+
]
46+
47+
48+
class MidContractActions(StrEnum):
49+
"""List of actions the middle contracts can perform."""
50+
51+
NOOP = "noop"
52+
SSTORE_TOGGLE = "sstore-toggle"
53+
REVERT = "revert"
54+
55+
56+
# Middle-action combinations: (call_opcode, side_contract_index).
57+
# Side-contract indices: 0=noop, 1=sstore-toggle, 2=reverting.
58+
MIDDLE_ACTIONS = [
59+
(op, t)
60+
for op in [
61+
Op.CALL,
62+
Op.CALLCODE,
63+
Op.DELEGATECALL,
64+
Op.STATICCALL,
65+
]
66+
for t in MidContractActions
67+
]
68+
69+
70+
@pytest.mark.parametrize(
71+
"update_storage_initial_value",
72+
range(3),
73+
ids=["initial0", "initial1", "initial2"],
74+
)
75+
@pytest.mark.parametrize(
76+
"call_4, call_4_target",
77+
MIDDLE_ACTIONS,
78+
ids=[f"call_4_{op}_{target}" for op, target in MIDDLE_ACTIONS],
79+
)
80+
@pytest.mark.parametrize(
81+
"call_3",
82+
[Op.STATICCALL, Op.CALL, Op.CALLCODE, Op.DELEGATECALL],
83+
)
84+
@pytest.mark.parametrize(
85+
"call_2, call_2_target",
86+
MIDDLE_ACTIONS,
87+
ids=[f"call_2_{op}_{target}" for op, target in MIDDLE_ACTIONS],
88+
)
89+
@pytest.mark.parametrize(
90+
"call_1",
91+
[Op.CALL, Op.CALLCODE, Op.DELEGATECALL],
92+
)
93+
def test_sstore_combinations_initial(
94+
state_test: StateTestFiller,
95+
pre: Alloc,
96+
fork: Fork,
97+
update_storage_initial_value: int,
98+
call_1: Op,
99+
call_2: Op,
100+
call_2_target: MidContractActions,
101+
call_3: Op,
102+
call_4: Op,
103+
call_4_target: MidContractActions,
104+
) -> None:
105+
"""Test SSTORE with four interleaved calls."""
106+
sender = pre.fund_eoa()
107+
side = {
108+
# Noop / balance-only (no executable code)
109+
MidContractActions.NOOP: pre.deploy_contract(
110+
Bytecode(),
111+
balance=10,
112+
storage={0: 1, 1: 1, 2: 1},
113+
),
114+
# SSTORE-toggle: flip slots 1..16, then set slot 1 = 1
115+
MidContractActions.SSTORE_TOGGLE: pre.deploy_contract(
116+
code=sum(
117+
Op.SSTORE(key=i, value=0x1) + Op.SSTORE(key=i, value=0x0)
118+
for i in range(0x1, 0x10 + 1)
119+
)
120+
+ Op.SSTORE(key=0x1, value=0x1)
121+
+ Op.STOP,
122+
),
123+
# Reverting contract
124+
MidContractActions.REVERT: pre.deploy_contract(
125+
code=Op.REVERT(offset=0x0, size=0x20) + Op.STOP,
126+
storage={0: 2, 1: 2, 2: 2},
127+
),
128+
}
129+
130+
update_contract = pre.deploy_contract(
131+
code=Op.SSTORE(key=0x0, value=0x0)
132+
+ Op.SSTORE(key=0x1, value=0x1)
133+
+ Op.SSTORE(key=0x2, value=0x2)
134+
+ Op.STOP,
135+
storage={
136+
0: update_storage_initial_value,
137+
1: update_storage_initial_value,
138+
2: update_storage_initial_value,
139+
}
140+
if update_storage_initial_value > 0
141+
else {},
142+
)
143+
sstore_toggle = side[MidContractActions.SSTORE_TOGGLE]
144+
145+
call_gas = 0x493E0
146+
147+
initcode = (
148+
Op.MSTORE(offset=0x64, value=0x0)
149+
+ Op.POP(
150+
call_1(
151+
gas=call_gas,
152+
address=update_contract,
153+
args_size=0x20,
154+
)
155+
)
156+
+ Op.POP(call_2(gas=call_gas, address=side[call_2_target]))
157+
+ Op.POP(
158+
call_3(
159+
gas=call_gas,
160+
address=update_contract,
161+
args_size=0x20,
162+
)
163+
)
164+
+ Op.POP(call_4(gas=call_gas, address=side[call_4_target]))
165+
+ Op.CALL(gas=call_gas * 2, address=sstore_toggle)
166+
+ Op.STOP
167+
)
168+
169+
tx = Transaction(
170+
sender=sender,
171+
to=None,
172+
data=initcode,
173+
gas_limit=2_000_000,
174+
value=1,
175+
protected=fork.supports_protected_txs(),
176+
)
177+
178+
post = {
179+
sstore_toggle: Account(storage={1: 1}),
180+
compute_create_address(address=sender, nonce=0): Account(nonce=1),
181+
}
182+
183+
state_test(pre=pre, post=post, tx=tx)
184+
185+
186+
@pytest.mark.parametrize(
187+
"update_storage_initial_value",
188+
range(3),
189+
ids=["initial0", "initial1", "initial2"],
190+
)
191+
def test_sstore_combinations_initial_staticcall_only(
192+
state_test: StateTestFiller,
193+
pre: Alloc,
194+
fork: Fork,
195+
update_storage_initial_value: int,
196+
) -> None:
197+
"""Base case: STATICCALL to update-contract only."""
198+
sender = pre.fund_eoa()
199+
200+
update_contract = pre.deploy_contract(
201+
code=Op.SSTORE(key=0x0, value=0x0)
202+
+ Op.SSTORE(key=0x1, value=0x1)
203+
+ Op.SSTORE(key=0x2, value=0x2)
204+
+ Op.STOP,
205+
storage={
206+
0: update_storage_initial_value,
207+
1: update_storage_initial_value,
208+
2: update_storage_initial_value,
209+
}
210+
if update_storage_initial_value > 0
211+
else {},
212+
)
213+
sstore_toggle = pre.deploy_contract(
214+
code=sum(
215+
Op.SSTORE(key=i, value=0x1) + Op.SSTORE(key=i, value=0x0)
216+
for i in range(0x1, 0x10 + 1)
217+
)
218+
+ Op.SSTORE(key=0x1, value=0x1)
219+
+ Op.STOP,
220+
)
221+
222+
call_gas = 0x493E0
223+
224+
initcode = (
225+
Op.MSTORE(offset=0x64, value=0x0)
226+
+ Op.POP(
227+
Op.STATICCALL(
228+
gas=call_gas,
229+
address=update_contract,
230+
args_size=0x20,
231+
)
232+
)
233+
+ Op.CALL(gas=call_gas * 2, address=sstore_toggle)
234+
+ Op.STOP
235+
)
236+
237+
tx = Transaction(
238+
sender=sender,
239+
to=None,
240+
data=initcode,
241+
gas_limit=2_000_000,
242+
value=1,
243+
protected=fork.supports_protected_txs(),
244+
)
245+
246+
post = {
247+
sstore_toggle: Account(storage={1: 1}),
248+
compute_create_address(address=sender, nonce=0): Account(nonce=1),
249+
}
250+
251+
state_test(pre=pre, post=post, tx=tx)

tests/ported_static/stTimeConsuming/test_sstore_combinations_initial00_2_paris.py

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -7,135 +7,3 @@
77
@manually-enhanced: Do not overwrite. This test has been manually reviewed and
88
enhanced.
99
"""
10-
11-
import pytest
12-
from execution_testing import (
13-
Account,
14-
Alloc,
15-
Bytecode,
16-
StateTestFiller,
17-
Transaction,
18-
compute_create_address,
19-
)
20-
from execution_testing.forks import Fork
21-
from execution_testing.vm import Op
22-
23-
REFERENCE_SPEC_GIT_PATH = "N/A"
24-
REFERENCE_SPEC_VERSION = "N/A"
25-
26-
27-
@pytest.mark.ported_from(
28-
[
29-
"state_tests/stTimeConsuming/sstore_combinations_initial00_2_ParisFiller.json" # noqa: E501
30-
],
31-
)
32-
@pytest.mark.valid_from("Byzantium")
33-
@pytest.mark.slow
34-
@pytest.mark.parametrize(
35-
"d",
36-
range(424),
37-
ids=lambda d: f"d{d}",
38-
)
39-
def test_sstore_combinations_initial00_2_paris(
40-
state_test: StateTestFiller,
41-
pre: Alloc,
42-
fork: Fork,
43-
d: int,
44-
) -> None:
45-
"""Sstore 0 -> {calltype} -> change to {0, 1, 2} |-> {calltype} ->..."""
46-
sender = pre.fund_eoa()
47-
# Source: lll
48-
# { [[0]] 0 [[1]] 1 [[2]] 2 }
49-
contract_0 = pre.deploy_contract( # noqa: F841
50-
code=Op.SSTORE(key=0x0, value=0x0)
51-
+ Op.SSTORE(key=0x1, value=0x1)
52-
+ Op.SSTORE(key=0x2, value=0x2)
53-
+ Op.STOP,
54-
)
55-
# Source: lll
56-
# { [[0]] 0 [[1]] 1 [[2]] 2 }
57-
contract_1 = pre.deploy_contract( # noqa: F841
58-
code=Op.SSTORE(key=0x0, value=0x0)
59-
+ Op.SSTORE(key=0x1, value=0x1)
60-
+ Op.SSTORE(key=0x2, value=0x2)
61-
+ Op.STOP,
62-
storage={0: 1, 1: 1, 2: 1},
63-
)
64-
# Source: lll
65-
# { [[0]] 0 [[1]] 1 [[2]] 2 }
66-
contract_2 = pre.deploy_contract( # noqa: F841
67-
code=Op.SSTORE(key=0x0, value=0x0)
68-
+ Op.SSTORE(key=0x1, value=0x1)
69-
+ Op.SSTORE(key=0x2, value=0x2)
70-
+ Op.STOP,
71-
storage={0: 2, 1: 2, 2: 2},
72-
)
73-
contract_3 = pre.deploy_contract(
74-
Bytecode(),
75-
balance=10,
76-
storage={0: 1, 1: 1, 2: 1},
77-
)
78-
# Source: lll
79-
# { [[1]] 1 [[1]] 0 [[2]] 1 [[2]] 0 [[3]] 1 [[3]] 0 [[4]] 1 [[4]] 0 [[5]] 1 [[5]] 0 [[6]] 1 [[6]] 0 [[7]] 1 [[7]] 0 [[8]] 1 [[8]] 0 [[9]] 1 [[9]] 0 [[10]] 1 [[10]] 0 [[11]] 1 [[11]] 0 [[12]] 1 [[12]] 0 [[13]] 1 [[13]] 0 [[14]] 1 [[14]] 0 [[15]] 1 [[15]] 0 [[16]] 1 [[16]] 0 [[1]] 1 } # noqa: E501
80-
contract_4 = pre.deploy_contract( # noqa: F841
81-
code=sum(
82-
Op.SSTORE(key=i, value=0x1) + Op.SSTORE(key=i, value=0x0)
83-
for i in range(0x1, 0x10 + 1)
84-
)
85-
+ Op.SSTORE(key=0x1, value=0x1)
86-
+ Op.STOP,
87-
)
88-
# Source: lll
89-
# { (REVERT 0 32) }
90-
contract_5 = pre.deploy_contract( # noqa: F841
91-
code=Op.REVERT(offset=0x0, size=0x20) + Op.STOP,
92-
storage={0: 2, 1: 2, 2: 2},
93-
)
94-
95-
# Combinatorial initcode generator
96-
# 1728 entries = 3 x 12 x 4 x 12 (dims: outer to inner)
97-
# dim0: 1st change call type (3) - CALL, CALLCODE, DELEGATECALL
98-
# dim1: middle action 1 (12) - {CALL,CALLCODE,DELEGATECALL,STATICCALL} x {c3,c4,c5} # noqa: E501
99-
# dim2: 2nd change call type (4) - STATICCALL, CALL, CALLCODE, DELEGATECALL # noqa: E501
100-
# dim3: middle action 2 (12) - {CALL,CALLCODE,DELEGATECALL,STATICCALL} x {c3,c4,c5} # noqa: E501
101-
gas = 0x493E0
102-
dim0_types = [Op.CALL, Op.CALLCODE, Op.DELEGATECALL]
103-
dim2_types = [Op.STATICCALL, Op.CALL, Op.CALLCODE, Op.DELEGATECALL]
104-
call_types = [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL]
105-
contracts = [contract_3, contract_4, contract_5]
106-
change_contract = contract_0
107-
108-
idx = 0x1AA + d - 1 # 4-call index
109-
110-
call_1_op = dim0_types[idx // 576]
111-
call_2_op = call_types[(idx // 48) % 12 // 3]
112-
call_2_contract = contracts[(idx // 48) % 12 % 3]
113-
call_3_op = dim2_types[(idx // 12) % 4]
114-
call_4_op = call_types[idx % 12 // 3]
115-
call_4_contract = contracts[idx % 12 % 3]
116-
117-
initcode = (
118-
Op.MSTORE(offset=0x64, value=0x1AA + d)
119-
+ Op.POP(call_1_op(gas=gas, address=change_contract, args_size=0x20))
120-
+ Op.POP(call_2_op(gas=gas, address=call_2_contract))
121-
+ Op.POP(call_3_op(gas=gas, address=change_contract, args_size=0x20))
122-
+ Op.POP(call_4_op(gas=gas, address=call_4_contract))
123-
+ Op.CALL(gas=gas * 2, address=contract_4)
124-
+ Op.STOP
125-
)
126-
127-
tx = Transaction(
128-
sender=sender,
129-
to=None,
130-
data=initcode,
131-
gas_limit=2_000_000,
132-
value=1,
133-
protected=fork.supports_protected_txs(),
134-
)
135-
136-
post = {
137-
contract_4: Account(storage={1: 1}),
138-
compute_create_address(address=sender, nonce=0): Account(nonce=1),
139-
}
140-
141-
state_test(pre=pre, post=post, tx=tx)

0 commit comments

Comments
 (0)