Skip to content

Commit d4968fa

Browse files
feat(benchmark): add pure calldata transaction case (#1820)
* refactor: rename eth transfer cost * feat(benchmark): add empty payload test case * refactor: apply eip7623 for empty payload test * fix(benchmark): update max token in calldata formula * refactor(benchmark): rename test for block with full data payload
1 parent 70a0a82 commit d4968fa

File tree

1 file changed

+72
-6
lines changed

1 file changed

+72
-6
lines changed

tests/benchmark/test_worst_blocks.py

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
Block,
1616
BlockchainTestFiller,
1717
Environment,
18+
StateTestFiller,
1819
Transaction,
1920
)
2021

2122

2223
@pytest.fixture
23-
def iteration_count(eth_transfer_cost: int):
24+
def iteration_count(intrinsic_cost: int):
2425
"""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
2627

2728

2829
@pytest.fixture
@@ -32,8 +33,8 @@ def transfer_amount():
3233

3334

3435
@pytest.fixture
35-
def eth_transfer_cost(fork: Fork):
36-
"""Transaction gas limit."""
36+
def intrinsic_cost(fork: Fork):
37+
"""Transaction intrinsic cost."""
3738
intrinsic_cost = fork.transaction_intrinsic_cost_calculator()
3839
return intrinsic_cost()
3940

@@ -113,7 +114,7 @@ def test_block_full_of_ether_transfers(
113114
ether_transfer_case,
114115
iteration_count: int,
115116
transfer_amount: int,
116-
eth_transfer_cost: int,
117+
intrinsic_cost: int,
117118
):
118119
"""
119120
Single test for ether transfer scenarios.
@@ -137,7 +138,7 @@ def test_block_full_of_ether_transfers(
137138
Transaction(
138139
to=receiver,
139140
value=transfer_amount,
140-
gas_limit=eth_transfer_cost,
141+
gas_limit=intrinsic_cost,
141142
sender=next(senders),
142143
)
143144
)
@@ -156,3 +157,68 @@ def test_block_full_of_ether_transfers(
156157
blocks=[Block(txs=txs)],
157158
exclude_full_post_state_in_output=True,
158159
)
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

Comments
 (0)