Skip to content

Commit a5dbabd

Browse files
winsvegamarioevz
andauthored
feat(tests): port create selfdestruct store test (#1867)
* type(tests): convert create suicide store test * small improvements * fix: lint, add coverage change reason --------- Co-authored-by: Mario Vega <[email protected]>
1 parent 39e8316 commit a5dbabd

File tree

2 files changed

+153
-102
lines changed

2 files changed

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