Skip to content

Commit 28ca6de

Browse files
winsvegamarioevz
andauthored
type(tests): convert create suicide during init (#1871)
* type(tests): convert create suicide during init * Fixes, increase coverage * fix: Coverage script * Add coveraged missed reason --------- Co-authored-by: Mario Vega <[email protected]>
1 parent ae9b597 commit 28ca6de

6 files changed

+119
-285
lines changed

.github/workflows/coverage.yaml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,23 @@ jobs:
144144
if: ${{ steps.pre-patch-fill.outputs.any_modified_fixtures == 'true' || steps.ported-from.outputs.any_ported == 'true' }}
145145
run: |
146146
echo "=== Original BASE (main) test IDs ==="
147-
uv run python -c "import json; data=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS/.meta/index.json')); [print(tc['id']) for tc in data['test_cases']]"
147+
if [ -f "${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS/.meta/index.json" ]; then
148+
uv run python -c "import json; data=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS/.meta/index.json')); [print(tc['id']) for tc in data['test_cases']]"
149+
else
150+
echo "No BASE_TESTS/.meta/index.json found"
151+
fi
148152
echo "=== Ported PATCH test IDs ==="
149-
uv run python -c "import json; data=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS/.meta/index.json')); [print(tc['id']) for tc in data['test_cases']]"
153+
if [ -f "${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS/.meta/index.json" ]; then
154+
uv run python -c "import json; data=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS/.meta/index.json')); [print(tc['id']) for tc in data['test_cases']]"
155+
else
156+
echo "No PATCH_TESTS/.meta/index.json found"
157+
fi
150158
echo "=== SUMMARY ==="
151-
uv run python -c "import json; base=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS/.meta/index.json')); patch=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS/.meta/index.json')); print(f'BASE: {len(base[\"test_cases\"])} tests, PATCH: {len(patch[\"test_cases\"])} tests, Difference: {len(patch[\"test_cases\"]) - len(base[\"test_cases\"])}')"
159+
if [ -f "${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS/.meta/index.json" ] && [ -f "${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS/.meta/index.json" ]; then
160+
uv run python -c "import json; base=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS/.meta/index.json')); patch=json.load(open('${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS/.meta/index.json')); print(f'BASE: {len(base[\"test_cases\"])} tests, PATCH: {len(patch[\"test_cases\"])} tests, Difference: {len(patch[\"test_cases\"]) - len(base[\"test_cases\"])}')"
161+
else
162+
echo "No BASE_TESTS/.meta/index.json or PATCH_TESTS/.meta/index.json found"
163+
fi
152164
153165
- name: Run coverage of the BASE tests
154166
uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
"""Deploy contract that calls selfdestruct in it's initcode."""
2+
3+
from enum import Enum
4+
5+
import pytest
6+
7+
from ethereum_test_forks import Byzantium, Fork
8+
from ethereum_test_tools import (
9+
Account,
10+
Alloc,
11+
Environment,
12+
Initcode,
13+
StateTestFiller,
14+
Transaction,
15+
compute_create_address,
16+
)
17+
from ethereum_test_tools import Opcodes as Op
18+
19+
20+
class Operation(Enum):
21+
"""Enum for created contract actions."""
22+
23+
SUICIDE = 1
24+
SUICIDE_TO_ITSELF = 2
25+
26+
def __int__(self):
27+
"""Convert to int."""
28+
return int(self.value)
29+
30+
31+
@pytest.mark.ported_from(
32+
[
33+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_ContractSuicideDuringInit_ThenStoreThenReturnFiller.json",
34+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_ContractSuicideDuringInit_WithValueFiller.json",
35+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_ContractSuicideDuringInit_WithValueToItselfFiller.json",
36+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_ContractSuicideDuringInitFiller.json",
37+
],
38+
pr=["https://github.com/ethereum/execution-spec-tests/pull/1871"],
39+
coverage_missed_reason="Tip to coinbase, original test contains empty account.",
40+
)
41+
@pytest.mark.valid_from("Frontier")
42+
@pytest.mark.with_all_create_opcodes
43+
@pytest.mark.parametrize("transaction_create", [False, True])
44+
@pytest.mark.parametrize(
45+
"operation",
46+
[Operation.SUICIDE, Operation.SUICIDE_TO_ITSELF],
47+
)
48+
def test_create_suicide_during_transaction_create(
49+
state_test: StateTestFiller,
50+
fork: Fork,
51+
pre: Alloc,
52+
create_opcode: Op,
53+
operation: Operation,
54+
transaction_create: bool,
55+
):
56+
"""Contract init code calls suicide then measures different metrics."""
57+
if create_opcode != Op.CREATE and transaction_create:
58+
pytest.skip(f"Excluded: {create_opcode} with transaction_create=True")
59+
60+
sender = pre.fund_eoa()
61+
contract_deploy = pre.deploy_contract(
62+
code=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)
63+
+ create_opcode(size=Op.CALLDATASIZE(), value=Op.CALLVALUE())
64+
)
65+
contract_success = pre.deploy_contract(code=Op.SSTORE(1, 1))
66+
self_destruct_destination = pre.deploy_contract(code=Op.STOP)
67+
contract_after_suicide = pre.deploy_contract(code=Op.SSTORE(1, 1))
68+
69+
contract_initcode = Initcode(
70+
initcode_prefix=Op.CALL(address=contract_success, gas=Op.SUB(Op.GAS, 100_000))
71+
+ Op.SELFDESTRUCT(
72+
Op.ADDRESS if operation == Operation.SUICIDE_TO_ITSELF else self_destruct_destination
73+
)
74+
+ Op.CALL(address=contract_after_suicide, gas=Op.SUB(Op.GAS, 100_000)),
75+
deploy_code=Op.SSTORE(0, 1),
76+
)
77+
78+
expected_create_address = compute_create_address(
79+
address=sender if transaction_create else contract_deploy,
80+
nonce=1 if transaction_create else 0,
81+
initcode=contract_initcode,
82+
opcode=create_opcode,
83+
)
84+
85+
tx_value = 100
86+
tx = Transaction(
87+
gas_limit=1_000_000,
88+
to=None if transaction_create else contract_deploy,
89+
data=contract_initcode,
90+
value=tx_value,
91+
sender=sender,
92+
protected=fork >= Byzantium,
93+
)
94+
95+
post = {
96+
contract_success: Account(storage={1: 1}),
97+
self_destruct_destination: Account(
98+
balance=0 if operation == Operation.SUICIDE_TO_ITSELF else tx_value
99+
),
100+
contract_deploy: Account(storage={0: 0}),
101+
contract_after_suicide: Account(storage={1: 0}), # suicide eats all gas
102+
expected_create_address: Account.NONEXISTENT,
103+
}
104+
state_test(env=Environment(), pre=pre, post=post, tx=tx)

tests/static/state_tests/stCreateTest/CREATE_ContractSuicideDuringInitFiller.json

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

tests/static/state_tests/stCreateTest/CREATE_ContractSuicideDuringInit_ThenStoreThenReturnFiller.json

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

tests/static/state_tests/stCreateTest/CREATE_ContractSuicideDuringInit_WithValueFiller.json

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

0 commit comments

Comments
 (0)