Skip to content

Commit 410c1cc

Browse files
committed
type(tests): convert create suicide store test
1 parent 2a7a6d7 commit 410c1cc

File tree

3 files changed

+162
-106
lines changed

3 files changed

+162
-106
lines changed

tests/frontier/create/test_create_one_byte.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_FirstByte_loopFiller.yml",
2626
],
2727
pr=["https://github.com/ethereum/execution-spec-tests/pull/1615"],
28-
coverage_missed_reason=(
29-
"coinbase is deleted in original test (tx.gas_price==env.base_fee), "
30-
"opcodes lt, iszero, jump are no longer used"
31-
),
28+
# coverage_missed_reason=(
29+
# "coinbase is deleted in original test (tx.gas_price==env.base_fee), "
30+
# "opcodes lt, iszero, jump are no longer used"
31+
# ),
3232
)
3333
@pytest.mark.valid_from("Frontier")
3434
@pytest.mark.with_all_create_opcodes
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
"""
2+
Test dynamically created address is still callable and perform storage operations
3+
after being called for self destruct in a call.
4+
"""
5+
6+
from enum import Enum
7+
8+
import pytest
9+
10+
from ethereum_test_forks import Byzantium, Fork
11+
from ethereum_test_tools import (
12+
Account,
13+
Alloc,
14+
Case,
15+
Environment,
16+
Initcode,
17+
StateTestFiller,
18+
Storage,
19+
Switch,
20+
Transaction,
21+
compute_create_address,
22+
)
23+
from ethereum_test_tools import Opcodes as Op
24+
25+
26+
class Operation(Enum):
27+
"""Enum for created contract actions."""
28+
29+
SUICIDE = 1
30+
ADD_STORAGE = 2
31+
GET_STORAGE = 3
32+
33+
def __int__(self):
34+
"""Convert to int."""
35+
return int(self.value)
36+
37+
38+
@pytest.mark.ported_from(
39+
[
40+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_AcreateB_BSuicide_BStoreFiller.json",
41+
],
42+
pr=["https://github.com/ethereum/execution-spec-tests/pull/1867"],
43+
coverage_missed_reason="Converting solidity code result in following opcode not being used:"
44+
"PUSH29, DUP4, DUP8, SWAP2, ISZERO, AND, MUL, DIV, CALLVALUE, EXTCODESIZE",
45+
)
46+
@pytest.mark.valid_from("Frontier")
47+
@pytest.mark.with_all_create_opcodes
48+
def test_create_suicide_store(
49+
state_test: StateTestFiller,
50+
fork: Fork,
51+
pre: Alloc,
52+
create_opcode: Op,
53+
):
54+
"""
55+
Create dynamic contract that suicides, then called to push some storage
56+
and then called to return that storage value.
57+
"""
58+
tload_support = fork.valid_opcodes().count(Op.TLOAD)
59+
subcall_storage = 0x12
60+
suicide_initcode: Initcode = Initcode(
61+
deploy_code=Switch(
62+
cases=[
63+
Case(
64+
condition=Op.EQ(Op.CALLDATALOAD(0), int(Operation.SUICIDE)),
65+
action=Op.SELFDESTRUCT(0x11),
66+
),
67+
Case(
68+
condition=Op.EQ(Op.CALLDATALOAD(0), int(Operation.ADD_STORAGE)),
69+
action=Op.SSTORE(1, Op.ADD(Op.SLOAD(1), subcall_storage))
70+
+ (
71+
Op.TSTORE(1, Op.ADD(Op.TLOAD(1), subcall_storage))
72+
if tload_support
73+
else Op.STOP
74+
),
75+
),
76+
Case(
77+
condition=Op.EQ(Op.CALLDATALOAD(0), int(Operation.GET_STORAGE)),
78+
action=(
79+
Op.MSTORE(0, Op.ADD(Op.SLOAD(1), Op.TLOAD(1)))
80+
if tload_support
81+
else Op.MSTORE(0, Op.SLOAD(1))
82+
)
83+
+ Op.RETURN(0, 32),
84+
),
85+
],
86+
default_action=None,
87+
)
88+
)
89+
90+
sender = pre.fund_eoa()
91+
expect_post = Storage()
92+
93+
slot_create_result = 0
94+
slot_after_suicide_sstore_return = 1
95+
slot_program_success = 2
96+
create_contract = pre.deploy_contract(
97+
code=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)
98+
+ Op.SSTORE(slot_create_result, create_opcode(size=Op.CALLDATASIZE()))
99+
# Put some storage before suicide
100+
+ Op.MSTORE(64, int(Operation.ADD_STORAGE))
101+
+ Op.CALL(
102+
gas=Op.SUB(Op.GAS, 300_000),
103+
address=Op.SLOAD(slot_create_result),
104+
args_offset=64,
105+
args_size=32,
106+
)
107+
+ Op.MSTORE(64, int(Operation.SUICIDE))
108+
+ Op.CALL(
109+
gas=Op.SUB(Op.GAS, 300_000),
110+
address=Op.SLOAD(slot_create_result),
111+
args_offset=64,
112+
args_size=32,
113+
)
114+
# Put some storage after suicide
115+
+ Op.MSTORE(64, int(Operation.ADD_STORAGE))
116+
+ Op.CALL(
117+
gas=Op.SUB(Op.GAS, 300_000),
118+
address=Op.SLOAD(slot_create_result),
119+
args_offset=64,
120+
args_size=32,
121+
)
122+
+ Op.MSTORE(64, int(Operation.GET_STORAGE))
123+
+ Op.CALL(
124+
gas=Op.SUB(Op.GAS, 300_000),
125+
address=Op.SLOAD(0),
126+
args_offset=64,
127+
args_size=32,
128+
ret_offset=100,
129+
ret_size=32,
130+
)
131+
+ Op.SSTORE(slot_after_suicide_sstore_return, Op.MLOAD(100))
132+
+ Op.SSTORE(slot_program_success, 1)
133+
)
134+
135+
expected_create_address = compute_create_address(
136+
address=create_contract, nonce=1, initcode=suicide_initcode, opcode=create_opcode
137+
)
138+
expect_post[slot_create_result] = expected_create_address
139+
expect_post[slot_after_suicide_sstore_return] = (
140+
subcall_storage * 2 # added value before and after suicide
141+
+ (subcall_storage * 2 if tload_support else 0) # tload value added
142+
)
143+
expect_post[slot_program_success] = 1
144+
145+
tx = Transaction(
146+
gas_limit=1_000_000,
147+
to=create_contract,
148+
data=suicide_initcode,
149+
nonce=0,
150+
sender=sender,
151+
protected=fork >= Byzantium,
152+
)
153+
154+
post = {
155+
create_contract: Account(storage=expect_post),
156+
expected_create_address: Account.NONEXISTENT,
157+
}
158+
state_test(env=Environment(), pre=pre, post=post, tx=tx)

tests/static/state_tests/stCreateTest/CREATE_AcreateB_BSuicide_BStoreFiller.json

Lines changed: 0 additions & 102 deletions
This file was deleted.

0 commit comments

Comments
 (0)