Skip to content

Commit 1049a46

Browse files
committed
port intrinsic transaction gas tests from Ori
1 parent 624f60b commit 1049a46

File tree

3 files changed

+277
-0
lines changed

3 files changed

+277
-0
lines changed

converted-ethereum-tests.txt

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
([#1535](https://github.com/ethereum/execution-spec-tests/pull/1535))
2+
GeneralStateTests/stEIP1559/intrinsicCancun.json
3+
BlockchainTests/InvalidBlocks/bcEIP1559/intrinsicOrFail.json
4+
15
([#1056](https://github.com/ethereum/execution-spec-tests/pull/1056))
26
GeneralStateTests/VMTests/vmTests/calldatacopy.json
37

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""Defines EIP-2930 specification constants and functions."""
2+
3+
from dataclasses import dataclass
4+
from typing import List
5+
6+
from ethereum_test_tools import AccessList, Bytes
7+
8+
9+
@dataclass(frozen=True)
10+
class ReferenceSpec:
11+
"""Defines the reference spec version and git path."""
12+
13+
git_path: str
14+
version: str
15+
16+
17+
ref_spec_2930 = ReferenceSpec("EIPS/eip-2930.md", "cc6ed420006c13b6ef64b7987badc2966ad4508f")
18+
19+
20+
# Constants
21+
@dataclass(frozen=True)
22+
class Spec:
23+
"""
24+
Parameters from the EIP-2930 specifications as defined at
25+
https://eips.ethereum.org/EIPS/eip-2930#specification.
26+
"""
27+
28+
ACCESS_LIST_ADDRESS_COST = 2400
29+
ACCESS_LIST_STORAGE_KEY_COST = 1900
30+
31+
"""From EIP-2028"""
32+
TX_BASE_INTRINSIC_GAS = 21_000
33+
TX_DATA_ZERO_BYTE_GAS = 4
34+
TX_DATA_NON_ZERO_BYTE_GAS = 16
35+
36+
37+
def compute_data_intrinsic_gas(data: Bytes) -> int:
38+
"""
39+
Compute tx.data intrinsic gas.
40+
41+
Args:
42+
data (bytes): The input data for the transaction.
43+
44+
Returns:
45+
int: The intrinsic gas for the data.
46+
47+
"""
48+
zero_bytes = data.count(0)
49+
non_zero_bytes = len(data) - zero_bytes
50+
return (
51+
Spec.TX_DATA_ZERO_BYTE_GAS * zero_bytes + Spec.TX_DATA_NON_ZERO_BYTE_GAS * non_zero_bytes
52+
)
53+
54+
55+
def compute_access_list_intrinsic_gas(access_list: List[AccessList]) -> int:
56+
"""
57+
Compute the intrinsic gas for an access list.
58+
59+
Access List Costs:
60+
- 2400 gas per address
61+
- 1900 gas per storage key
62+
63+
Args:
64+
access_list (List[AccessList]): List of access list entries.
65+
66+
Returns:
67+
int: Total intrinsic gas from the access list.
68+
69+
"""
70+
total_gas = 0
71+
for entry in access_list:
72+
total_gas += Spec.ACCESS_LIST_ADDRESS_COST
73+
total_gas += Spec.ACCESS_LIST_STORAGE_KEY_COST * len(entry.storage_keys)
74+
75+
return total_gas
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
"""
2+
abstract: Tests [EIP-2930: Access list transaction](https://eips.ethereum.org/EIPS/eip-2930).
3+
Original test by Ori: https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1559/intrinsicGen.js.
4+
"""
5+
6+
from typing import List
7+
8+
import pytest
9+
10+
from ethereum_test_tools import (
11+
AccessList,
12+
Address,
13+
Alloc,
14+
Bytes,
15+
Environment,
16+
Hash,
17+
StateTestFiller,
18+
Transaction,
19+
TransactionException,
20+
)
21+
from ethereum_test_tools import Opcodes as Op
22+
23+
from .spec import (
24+
Spec,
25+
compute_access_list_intrinsic_gas,
26+
compute_data_intrinsic_gas,
27+
ref_spec_2930,
28+
)
29+
30+
REFERENCE_SPEC_GIT_PATH = ref_spec_2930.git_path
31+
REFERENCE_SPEC_VERSION = ref_spec_2930.version
32+
33+
pytestmark = pytest.mark.valid_from("Berlin")
34+
35+
36+
@pytest.mark.parametrize(
37+
"data",
38+
[
39+
pytest.param(Bytes(b""), id="data_empty"),
40+
pytest.param(Bytes(b"0x00"), id="data_1_zero_byte"),
41+
pytest.param(Bytes(b"0x00000000"), id="data_4_zero_byte"),
42+
pytest.param(Bytes(b"0xFF"), id="data_1_non_zero_byte"),
43+
pytest.param(Bytes(b"0x00FF"), id="data_1_zero_byte_1_non_zero_byte"),
44+
pytest.param(Bytes(b"0xFE00"), id="data_1_zero_byte_1_non_zero_byte_reversed"),
45+
pytest.param(Bytes(b"0x0102030405060708090A0B0C0D0E0F10"), id="data_set_1"),
46+
pytest.param(
47+
Bytes(b"0x0102030405060708090A0B0C0D0E0F101112131415161718191a1b1c1d1e1f20"),
48+
id="data_set_1",
49+
),
50+
pytest.param(
51+
Bytes(b"0x00010203040506000708090A0B0C0D0E0F10111200131415161718191a1b1c1d1e1f"),
52+
id="data_set_2",
53+
),
54+
pytest.param(
55+
Bytes(b"0x01020304050607080910111213141516171819202122232425262728293031"),
56+
id="data_set_31_bytes",
57+
),
58+
pytest.param(
59+
Bytes(b"0x000102030405060708090A0B0C0D0E0F101112131415161718191a1b1c1d1e1f"),
60+
id="data_set_32_bytes",
61+
),
62+
pytest.param(
63+
Bytes(b"0x010203040506070809101112131415161718192021222324252627282930313233"),
64+
id="data_set_33_bytes",
65+
),
66+
pytest.param(
67+
Bytes(b"0x000000000000000000000000000000000000000000000000000000000000000000"),
68+
id="data_set_33_empty_bytes",
69+
),
70+
pytest.param(
71+
Bytes(
72+
b"0x000000000000000000000000000000000000000000000000000000000000000000010203040506070809101112131415161718192021222324252627282930313233"
73+
),
74+
id="data_set_66_bytes_half_zeros",
75+
),
76+
],
77+
)
78+
@pytest.mark.parametrize(
79+
"access_list",
80+
[
81+
pytest.param([], id="access_list_empty"),
82+
pytest.param(
83+
[AccessList(address=Address(1), storage_keys=[])],
84+
id="access_list_1_address_empty_keys",
85+
),
86+
pytest.param(
87+
[AccessList(address=Address(1), storage_keys=[Hash("0x60A7", left_padding=True)])],
88+
id="access_list_1_address_1_keys",
89+
),
90+
pytest.param(
91+
[
92+
AccessList(
93+
address=Address(1),
94+
storage_keys=[
95+
Hash("0x60A7", left_padding=True),
96+
Hash("0x60A8", left_padding=True),
97+
],
98+
)
99+
],
100+
id="access_list_1_address_2_keys",
101+
),
102+
pytest.param(
103+
[
104+
AccessList(address=Address(1), storage_keys=[]),
105+
AccessList(address=Address(2), storage_keys=[]),
106+
],
107+
id="access_list_2_address_empty_keys",
108+
),
109+
pytest.param(
110+
[
111+
AccessList(address=Address(1), storage_keys=[]),
112+
AccessList(address=Address(2), storage_keys=[Hash("0x60A7", left_padding=True)]),
113+
],
114+
id="access_list_2_address_1_keys",
115+
),
116+
pytest.param(
117+
[
118+
AccessList(address=Address(1), storage_keys=[Hash("0x60A7", left_padding=True)]),
119+
AccessList(address=Address(2), storage_keys=[Hash("0x60A8", left_padding=True)]),
120+
],
121+
id="access_list_2_address_2_keys",
122+
),
123+
pytest.param(
124+
[
125+
AccessList(
126+
address=Address(1),
127+
storage_keys=[
128+
Hash("0x60A7", left_padding=True),
129+
Hash("0x60A8", left_padding=True),
130+
],
131+
),
132+
AccessList(address=Address(2), storage_keys=[]),
133+
],
134+
id="access_list_2_address_2_keys_inversion",
135+
),
136+
pytest.param(
137+
[
138+
AccessList(
139+
address=Address(1),
140+
storage_keys=[
141+
Hash("0xce11", left_padding=True),
142+
],
143+
),
144+
AccessList(
145+
address=Address(2),
146+
storage_keys=[
147+
Hash("0x60A7", left_padding=True),
148+
],
149+
),
150+
*[
151+
AccessList(
152+
address=Address(i),
153+
storage_keys=[
154+
Hash("0x600D", left_padding=True),
155+
Hash("0x0BAD", left_padding=True),
156+
Hash("0x60A7", left_padding=True),
157+
Hash("0xBEEF", left_padding=True),
158+
],
159+
)
160+
for i in range(3, 13) # 3 to 12 inclusive (10 entries)
161+
],
162+
],
163+
id="access_list_12_address_42_keys",
164+
),
165+
],
166+
)
167+
@pytest.mark.parametrize(
168+
"below_intrinsic",
169+
[
170+
pytest.param(False),
171+
pytest.param(True, marks=pytest.mark.exception_test),
172+
],
173+
)
174+
def test_tx_intrinsic_gas(
175+
state_test: StateTestFiller,
176+
pre: Alloc,
177+
data: Bytes,
178+
access_list: List[AccessList],
179+
below_intrinsic: bool,
180+
):
181+
"""Transaction intrinsic gas calculation on EIP1559."""
182+
tx = Transaction(
183+
ty=0x1,
184+
chain_id=0x01,
185+
sender=pre.fund_eoa(),
186+
to=pre.deploy_contract(code=Op.SSTORE(0, Op.ADD(1, 1))),
187+
data=data,
188+
access_list=access_list,
189+
gas_limit=Spec.TX_BASE_INTRINSIC_GAS
190+
+ compute_data_intrinsic_gas(data)
191+
+ compute_access_list_intrinsic_gas(access_list)
192+
+ (-1 if below_intrinsic else 0),
193+
error=TransactionException.INTRINSIC_GAS_TOO_LOW if below_intrinsic else None,
194+
gas_price=10,
195+
protected=True,
196+
)
197+
198+
state_test(env=Environment(), pre=pre, post={}, tx=tx)

0 commit comments

Comments
 (0)