Skip to content

Commit 27b523f

Browse files
temp
1 parent 8529a72 commit 27b523f

File tree

1 file changed

+117
-48
lines changed

1 file changed

+117
-48
lines changed

tests/benchmark/test_worst_stateful_opcodes.py

Lines changed: 117 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
Account,
1818
Address,
1919
Alloc,
20+
AuthorizationTuple,
2021
Block,
2122
Bytecode,
2223
Environment,
@@ -285,7 +286,7 @@ def test_worst_storage_access_cold(
285286
fork: Fork,
286287
storage_action: StorageAction,
287288
absent_slots: bool,
288-
env: Environment,
289+
tx_gas_limit_cap: int,
289290
gas_benchmark_value: int,
290291
tx_result: TransactionResult,
291292
) -> None:
@@ -328,12 +329,13 @@ def test_worst_storage_access_cold(
328329
# Add costs jump-logic costs
329330
loop_cost += (
330331
gas_costs.G_JUMPDEST # Prefix Jumpdest
331-
+ gas_costs.G_VERY_LOW * 7 # ISZEROs, PUSHs, SWAPs, SUB, DUP
332+
+ gas_costs.G_VERY_LOW * 5 # GT, PUSHs, SWAPs, SUB, DUP
333+
+ gas_costs.G_MID # SELFBALANCE
332334
+ gas_costs.G_HIGH # JUMPI
333335
)
334336

335337
prefix_cost = (
336-
gas_costs.G_VERY_LOW # Target slots push
338+
gas_costs.G_VERY_LOW * 2 # CALLDATALOAD(0)
337339
)
338340

339341
suffix_cost = 0
@@ -348,14 +350,15 @@ def test_worst_storage_access_cold(
348350
- prefix_cost
349351
- suffix_cost
350352
) // loop_cost
353+
351354
if tx_result == TransactionResult.OUT_OF_GAS:
352355
# Add an extra slot to make it run out-of-gas
353356
num_target_slots += 1
354357

355-
code_prefix = Op.PUSH4(num_target_slots) + Op.JUMPDEST
358+
code_prefix = Op.CALLDATALOAD(0) + Op.JUMPDEST
356359
code_loop = execution_code_body + Op.JUMPI(
357360
len(code_prefix) - 1,
358-
Op.PUSH1(1) + Op.SWAP1 + Op.SUB + Op.DUP1 + Op.ISZERO + Op.ISZERO,
361+
Op.PUSH1(1) + Op.ADD + Op.DUP1 + Op.SELFBALANCE + Op.GT,
359362
)
360363
execution_code = code_prefix + code_loop
361364

@@ -366,57 +369,123 @@ def test_worst_storage_access_cold(
366369

367370
execution_code_address = pre.deploy_contract(code=execution_code)
368371

369-
total_gas_used = (
370-
num_target_slots * loop_cost
371-
+ intrinsic_gas_cost_calc()
372-
+ prefix_cost
373-
+ suffix_cost
374-
)
372+
blocks = []
373+
target_addr = execution_code_address
375374

376-
# Contract creation
377-
slots_init = Bytecode()
375+
# Setup the target address
378376
if not absent_slots:
379-
slots_init = Op.PUSH4(num_target_slots) + While(
380-
body=Op.SSTORE(Op.DUP1, Op.DUP1),
381-
condition=Op.PUSH1(1)
382-
+ Op.SWAP1
383-
+ Op.SUB
384-
+ Op.DUP1
385-
+ Op.ISZERO
386-
+ Op.ISZERO,
377+
init_prefix = Op.CALLDATALOAD(0) + Op.JUMPDEST
378+
init_loop = Op.SSTORE(Op.DUP1, Op.DUP1)
379+
init_condition = Op.JUMPI(
380+
len(init_prefix) - 1,
381+
Op.PUSH1(1) + Op.ADD + Op.DUP1 + Op.SELFBALANCE + Op.GT,
387382
)
383+
init_contract = init_prefix + init_loop + init_condition
388384

389-
# To create the contract, we apply the slots_init code to initialize the
390-
# storage slots (int the case of absent_slots=False) and then copy the
391-
# execution code to the contract.
392-
creation_code = (
393-
slots_init
394-
+ Op.EXTCODECOPY(
395-
address=execution_code_address,
396-
dest_offset=0,
397-
offset=0,
398-
size=Op.EXTCODESIZE(execution_code_address),
385+
target_addr = pre.fund_eoa(
386+
amount=0, delegation=pre.deploy_contract(code=init_contract)
399387
)
400-
+ Op.RETURN(0, Op.MSIZE)
401-
)
402-
sender_addr = pre.fund_eoa()
403-
setup_tx = Transaction(
404-
to=None,
405-
gas_limit=env.gas_limit,
406-
data=creation_code,
407-
sender=sender_addr,
408-
)
409388

410-
blocks = [Block(txs=[setup_tx])]
389+
init_prefix_overhead = gas_costs.G_VERY_LOW * 2 + gas_costs.G_JUMPDEST
390+
init_loop_overhead = (
391+
gas_costs.G_VERY_LOW * 2 + gas_costs.G_WARM_ACCOUNT_ACCESS
392+
)
393+
init_condition_overhead = (
394+
gas_costs.G_VERY_LOW * 5 + gas_costs.G_MID + gas_costs.G_HIGH
395+
)
396+
init_total_overhead = (
397+
init_prefix_overhead + init_loop_overhead + init_condition_overhead
398+
)
399+
iteration_count = (
400+
gas_benchmark_value - intrinsic_gas_cost_calc()
401+
) // init_total_overhead
411402

412-
contract_address = compute_create_address(address=sender_addr, nonce=0)
403+
tx_count = gas_benchmark_value // tx_gas_limit_cap
404+
total_txs = []
405+
for i in range(tx_count * 2):
406+
tx = Transaction(
407+
to=target_addr,
408+
data=Hash(i * iteration_count),
409+
value=iteration_count,
410+
gas_limit=tx_gas_limit_cap,
411+
sender=pre.fund_eoa(),
412+
)
413+
total_txs.append(tx)
414+
blocks.append(Block(txs=total_txs[:tx_count]))
415+
blocks.append(Block(txs=total_txs[tx_count:]))
413416

414-
op_tx = Transaction(
415-
to=contract_address,
416-
gas_limit=gas_benchmark_value,
417-
sender=pre.fund_eoa(),
418-
)
419-
blocks.append(Block(txs=[op_tx]))
417+
tx = Transaction(
418+
to=execution_code_address,
419+
gas_limit=tx_gas_limit_cap,
420+
sender=pre.fund_eoa(),
421+
authorization_list=[
422+
AuthorizationTuple(
423+
address=execution_code_address,
424+
nonce=target_addr.nonce,
425+
signer=target_addr,
426+
)
427+
],
428+
)
429+
blocks.append(Block(txs=[tx]))
430+
431+
attack_txs = []
432+
gas_remaining = gas_benchmark_value
433+
total_iteration = 0
434+
total_gas_used = 0
435+
while gas_remaining > 0:
436+
gas_available = min(gas_remaining, tx_gas_limit_cap)
437+
438+
# Calculate minimum gas needed for at least one iteration
439+
min_gas_needed = (
440+
intrinsic_gas_cost_calc() + prefix_cost + loop_cost + suffix_cost
441+
)
442+
if gas_available < min_gas_needed:
443+
break
444+
445+
# Calculate iterations accounting for all overhead costs
446+
if tx_result == TransactionResult.OUT_OF_GAS:
447+
# For OUT_OF_GAS, add an extra iteration to run out of gas
448+
iterations = (
449+
(
450+
gas_available
451+
- intrinsic_gas_cost_calc()
452+
- prefix_cost
453+
- suffix_cost
454+
)
455+
// loop_cost
456+
) + 1
457+
tx_gas_used = (
458+
gas_available # Transaction will use all available gas
459+
)
460+
else:
461+
# For SUCCESS and REVERT, calculate iterations properly
462+
iterations = (
463+
gas_available
464+
- intrinsic_gas_cost_calc()
465+
- prefix_cost
466+
- suffix_cost
467+
) // loop_cost
468+
tx_gas_used = (
469+
intrinsic_gas_cost_calc()
470+
+ prefix_cost
471+
+ loop_cost * iterations
472+
+ suffix_cost
473+
)
474+
475+
attack_txs.append(
476+
Transaction(
477+
to=execution_code_address,
478+
data=Hash(total_iteration),
479+
value=iterations,
480+
gas_limit=gas_available,
481+
sender=pre.fund_eoa(),
482+
)
483+
)
484+
gas_remaining -= gas_available
485+
total_iteration += iterations
486+
total_gas_used += tx_gas_used
487+
488+
blocks.append(Block(txs=attack_txs))
420489

421490
benchmark_test(
422491
blocks=blocks,

0 commit comments

Comments
 (0)