15
15
Block ,
16
16
BlockchainTestFiller ,
17
17
Environment ,
18
+ StateTestFiller ,
18
19
Transaction ,
19
20
)
20
21
21
22
22
23
@pytest .fixture
23
- def iteration_count (eth_transfer_cost : int ):
24
+ def iteration_count (intrinsic_cost : int ):
24
25
"""Calculate the number of iterations based on the gas limit and intrinsic cost."""
25
- return Environment ().gas_limit // eth_transfer_cost
26
+ return Environment ().gas_limit // intrinsic_cost
26
27
27
28
28
29
@pytest .fixture
@@ -32,8 +33,8 @@ def transfer_amount():
32
33
33
34
34
35
@pytest .fixture
35
- def eth_transfer_cost (fork : Fork ):
36
- """Transaction gas limit ."""
36
+ def intrinsic_cost (fork : Fork ):
37
+ """Transaction intrinsic cost ."""
37
38
intrinsic_cost = fork .transaction_intrinsic_cost_calculator ()
38
39
return intrinsic_cost ()
39
40
@@ -113,7 +114,7 @@ def test_block_full_of_ether_transfers(
113
114
ether_transfer_case ,
114
115
iteration_count : int ,
115
116
transfer_amount : int ,
116
- eth_transfer_cost : int ,
117
+ intrinsic_cost : int ,
117
118
):
118
119
"""
119
120
Single test for ether transfer scenarios.
@@ -137,7 +138,7 @@ def test_block_full_of_ether_transfers(
137
138
Transaction (
138
139
to = receiver ,
139
140
value = transfer_amount ,
140
- gas_limit = eth_transfer_cost ,
141
+ gas_limit = intrinsic_cost ,
141
142
sender = next (senders ),
142
143
)
143
144
)
@@ -156,3 +157,68 @@ def test_block_full_of_ether_transfers(
156
157
blocks = [Block (txs = txs )],
157
158
exclude_full_post_state_in_output = True ,
158
159
)
160
+
161
+
162
+ @pytest .fixture
163
+ def total_cost_floor_per_token ():
164
+ """Total cost floor per token."""
165
+ return 10
166
+
167
+
168
+ @pytest .mark .valid_from ("Prague" )
169
+ @pytest .mark .parametrize ("zero_byte" , [True , False ])
170
+ def test_block_full_data (
171
+ state_test : StateTestFiller ,
172
+ pre : Alloc ,
173
+ zero_byte : bool ,
174
+ intrinsic_cost : int ,
175
+ total_cost_floor_per_token : int ,
176
+ ):
177
+ """Test a block with empty payload."""
178
+ attack_gas_limit = Environment ().gas_limit
179
+
180
+ # Gas cost calculation based on EIP-7683: (https://eips.ethereum.org/EIPS/eip-7683)
181
+ #
182
+ # tx.gasUsed = 21000 + max(
183
+ # STANDARD_TOKEN_COST * tokens_in_calldata
184
+ # + execution_gas_used
185
+ # + isContractCreation * (32000 + INITCODE_WORD_COST * words(calldata)),
186
+ # TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata)
187
+ #
188
+ # Simplified in this test case:
189
+ # - No execution gas used (no opcodes are executed)
190
+ # - Not a contract creation (no initcode)
191
+ #
192
+ # Therefore:
193
+ # max_token_cost = max(STANDARD_TOKEN_COST, TOTAL_COST_FLOOR_PER_TOKEN)
194
+ # tx.gasUsed = 21000 + tokens_in_calldata * max_token_cost
195
+ #
196
+ # Since max(STANDARD_TOKEN_COST, TOTAL_COST_FLOOR_PER_TOKEN) = 10:
197
+ # tx.gasUsed = 21000 + tokens_in_calldata * 10
198
+ #
199
+ # Token accounting:
200
+ # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes
201
+ #
202
+ # So we calculate how many bytes we can fit into calldata based on available gas.
203
+
204
+ gas_available = attack_gas_limit - intrinsic_cost
205
+
206
+ # Calculate the token_in_calldata
207
+ max_tokens_in_calldata = gas_available // total_cost_floor_per_token
208
+ # Calculate the number of bytes that can be stored in the calldata
209
+ num_of_bytes = max_tokens_in_calldata if zero_byte else max_tokens_in_calldata // 4
210
+ byte_data = b"\x00 " if zero_byte else b"\xff "
211
+
212
+ tx = Transaction (
213
+ to = pre .fund_eoa (),
214
+ data = byte_data * num_of_bytes ,
215
+ gas_limit = attack_gas_limit ,
216
+ sender = pre .fund_eoa (),
217
+ )
218
+
219
+ state_test (
220
+ env = Environment (),
221
+ pre = pre ,
222
+ post = {},
223
+ tx = tx ,
224
+ )
0 commit comments