Skip to content

Commit 4cd19f1

Browse files
committed
refactor(test-tests): parametrize existing test oog case instead
1 parent ee3defe commit 4cd19f1

File tree

2 files changed

+55
-96
lines changed

2 files changed

+55
-96
lines changed

tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_opcodes.py

Lines changed: 54 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -529,113 +529,53 @@ def test_bal_delegatecall_and_oog(
529529

530530

531531
@pytest.mark.parametrize(
532-
"fails_at_extcodecopy",
533-
[True, False],
534-
ids=["oog_at_extcodecopy", "successful_extcodecopy"],
535-
)
536-
def test_bal_extcodecopy_and_oog(
537-
pre: Alloc,
538-
blockchain_test: BlockchainTestFiller,
539-
fork: Fork,
540-
fails_at_extcodecopy: bool,
541-
) -> None:
542-
"""
543-
Ensure BAL handles EXTCODECOPY and OOG during EXTCODECOPY appropriately.
544-
"""
545-
alice = pre.fund_eoa()
546-
gas_costs = fork.gas_costs()
547-
548-
# Create target contract with some code
549-
target_contract = pre.deploy_contract(
550-
code=Bytecode(Op.PUSH1(0x42) + Op.STOP)
551-
)
552-
553-
# Create contract that attempts to copy code from target
554-
extcodecopy_contract_code = Bytecode(
555-
Op.PUSH1(0) # size - copy 0 bytes to minimize memory expansion cost
556-
+ Op.PUSH1(0) # codeOffset
557-
+ Op.PUSH1(0) # destOffset
558-
+ Op.PUSH20(target_contract) # address
559-
+ Op.EXTCODECOPY # Copy code (cold access + base cost)
560-
+ Op.STOP
561-
)
562-
563-
extcodecopy_contract = pre.deploy_contract(code=extcodecopy_contract_code)
564-
565-
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
566-
intrinsic_gas_cost = intrinsic_gas_calculator()
567-
568-
# Costs:
569-
# - 4 PUSH operations = G_VERY_LOW * 4
570-
# - EXTCODECOPY cold = G_COLD_ACCOUNT_ACCESS + (G_COPY * words)
571-
# where words = ceil32(size) // 32 = ceil32(0) // 32 = 0
572-
push_cost = gas_costs.G_VERY_LOW * 4
573-
extcodecopy_cold_cost = (
574-
gas_costs.G_COLD_ACCOUNT_ACCESS
575-
) # + (G_COPY * 0) = 0
576-
tx_gas_limit = intrinsic_gas_cost + push_cost + extcodecopy_cold_cost
577-
578-
if fails_at_extcodecopy:
579-
# subtract 1 gas to ensure OOG at EXTCODECOPY
580-
tx_gas_limit -= 1
581-
582-
tx = Transaction(
583-
sender=alice,
584-
to=extcodecopy_contract,
585-
gas_limit=tx_gas_limit,
586-
)
587-
588-
block = Block(
589-
txs=[tx],
590-
expected_block_access_list=BlockAccessListExpectation(
591-
account_expectations={
592-
extcodecopy_contract: BalAccountExpectation.empty(),
593-
# Target should only appear if EXTCODECOPY succeeded
594-
**(
595-
{target_contract: None}
596-
if fails_at_extcodecopy
597-
else {target_contract: BalAccountExpectation.empty()}
598-
),
599-
}
600-
),
601-
)
602-
603-
blockchain_test(
604-
pre=pre,
605-
blocks=[block],
606-
post={
607-
alice: Account(nonce=1),
608-
extcodecopy_contract: Account(),
609-
target_contract: Account(),
610-
},
611-
)
612-
613-
614-
@pytest.mark.parametrize(
615-
"memory_offset,copy_size,gas_shortfall",
532+
"oog_scenario,memory_offset,copy_size",
616533
[
617-
pytest.param(0x10000, 32, "large", id="large_offset"),
618-
pytest.param(256, 32, "boundary", id="boundary"),
534+
pytest.param("success", 0, 0, id="successful_extcodecopy"),
535+
pytest.param("oog_at_cold_access", 0, 0, id="oog_at_cold_access"),
536+
pytest.param(
537+
"oog_at_memory_large_offset",
538+
0x10000,
539+
32,
540+
id="oog_at_memory_large_offset",
541+
),
542+
pytest.param(
543+
"oog_at_memory_boundary",
544+
256,
545+
32,
546+
id="oog_at_memory_boundary",
547+
),
619548
],
620549
)
621-
def test_bal_extcodecopy_oog_at_memory_expansion(
550+
def test_bal_extcodecopy_and_oog(
622551
pre: Alloc,
623552
blockchain_test: BlockchainTestFiller,
624553
fork: Fork,
554+
oog_scenario: str,
625555
memory_offset: int,
626556
copy_size: int,
627-
gas_shortfall: str,
628557
) -> None:
629558
"""
630-
Test EXTCODECOPY OOG at memory expansion - target should NOT appear in BAL.
559+
Ensure BAL handles EXTCODECOPY and OOG during EXTCODECOPY appropriately.
560+
561+
Tests various OOG scenarios:
562+
- success: EXTCODECOPY completes, target appears in BAL
563+
- oog_at_cold_access: OOG before cold access, target NOT in BAL
564+
- oog_at_memory_large_offset: OOG at memory expansion (large offset),
565+
target NOT in BAL
566+
- oog_at_memory_boundary: OOG at memory expansion (boundary case),
567+
target NOT in BAL
631568
632569
Gas for all components (cold access + copy + memory expansion) must be
633570
checked BEFORE recording account access.
634571
"""
635572
alice = pre.fund_eoa()
636573
gas_costs = fork.gas_costs()
637574

638-
target_contract = pre.deploy_contract(code=Bytecode(Op.STOP))
575+
# Create target contract with some code
576+
target_contract = pre.deploy_contract(
577+
code=Bytecode(Op.PUSH1(0x42) + Op.STOP)
578+
)
639579

640580
# Build EXTCODECOPY contract with appropriate PUSH sizes
641581
if memory_offset <= 0xFF:
@@ -647,8 +587,8 @@ def test_bal_extcodecopy_oog_at_memory_expansion(
647587

648588
extcodecopy_contract_code = Bytecode(
649589
Op.PUSH1(copy_size)
650-
+ Op.PUSH1(0)
651-
+ dest_push
590+
+ Op.PUSH1(0) # codeOffset
591+
+ dest_push # destOffset
652592
+ Op.PUSH20(target_contract)
653593
+ Op.EXTCODECOPY
654594
+ Op.STOP
@@ -659,20 +599,35 @@ def test_bal_extcodecopy_oog_at_memory_expansion(
659599
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
660600
intrinsic_gas_cost = intrinsic_gas_calculator()
661601

602+
# Calculate costs
662603
push_cost = gas_costs.G_VERY_LOW * 4
663604
cold_access_cost = gas_costs.G_COLD_ACCOUNT_ACCESS
664605
copy_cost = gas_costs.G_COPY * ((copy_size + 31) // 32)
665606

666-
if gas_shortfall == "large":
607+
if oog_scenario == "success":
608+
# Provide enough gas for everything including memory expansion
609+
words = (memory_offset + copy_size + 31) // 32
610+
memory_cost = (words * gas_costs.G_MEMORY) + (words * words // 512)
611+
execution_cost = push_cost + cold_access_cost + copy_cost + memory_cost
612+
tx_gas_limit = intrinsic_gas_cost + execution_cost
613+
target_in_bal = True
614+
elif oog_scenario == "oog_at_cold_access":
615+
# Provide gas for pushes but 1 less than cold access cost
616+
execution_cost = push_cost + cold_access_cost
617+
tx_gas_limit = intrinsic_gas_cost + execution_cost - 1
618+
target_in_bal = False
619+
elif oog_scenario == "oog_at_memory_large_offset":
667620
# Provide gas for push + cold access + copy, but NOT memory expansion
668621
execution_cost = push_cost + cold_access_cost + copy_cost
669622
tx_gas_limit = intrinsic_gas_cost + execution_cost
670-
else:
623+
target_in_bal = False
624+
else: # oog_at_memory_boundary
671625
# Calculate memory cost and provide exactly 1 less than needed
672626
words = (memory_offset + copy_size + 31) // 32
673627
memory_cost = (words * gas_costs.G_MEMORY) + (words * words // 512)
674628
execution_cost = push_cost + cold_access_cost + copy_cost + memory_cost
675629
tx_gas_limit = intrinsic_gas_cost + execution_cost - 1
630+
target_in_bal = False
676631

677632
tx = Transaction(
678633
sender=alice,
@@ -685,7 +640,11 @@ def test_bal_extcodecopy_oog_at_memory_expansion(
685640
expected_block_access_list=BlockAccessListExpectation(
686641
account_expectations={
687642
extcodecopy_contract: BalAccountExpectation.empty(),
688-
target_contract: None,
643+
**(
644+
{target_contract: BalAccountExpectation.empty()}
645+
if target_in_bal
646+
else {target_contract: None}
647+
),
689648
}
690649
),
691650
)

tests/amsterdam/eip7928_block_level_access_lists/test_cases.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
| `test_bal_extcodesize_and_oog` | Ensure BAL handles OOG during EXTCODESIZE opcode execution correctly | Alice calls contract that attempts `EXTCODESIZE` opcode on cold target contract. Parameterized: (1) OOG at EXTCODESIZE opcode (insufficient gas), (2) Successful EXTCODESIZE execution. | For OOG case: BAL **MUST NOT** include target contract (wasn't accessed). For success case: BAL **MUST** include target contract in `account_changes`. | ✅ Completed |
5050
| `test_bal_call_and_oog` | Ensure BAL handles OOG during CALL opcode execution correctly | Alice calls contract that attempts `CALL` to cold target contract. Parameterized: (1) OOG at CALL opcode (insufficient gas), (2) Successful CALL execution. | For OOG case: BAL **MUST NOT** include target contract (wasn't accessed). For success case: BAL **MUST** include target contract in `account_changes`. | ✅ Completed |
5151
| `test_bal_delegatecall_and_oog` | Ensure BAL handles OOG during DELEGATECALL opcode execution correctly | Alice calls contract that attempts `DELEGATECALL` to cold target contract. Parameterized: (1) OOG at DELEGATECALL opcode (insufficient gas), (2) Successful DELEGATECALL execution. | For OOG case: BAL **MUST NOT** include target contract (wasn't accessed). For success case: BAL **MUST** include target contract in `account_changes`. | ✅ Completed |
52-
| `test_bal_extcodecopy_and_oog` | Ensure BAL handles OOG during EXTCODECOPY opcode execution correctly | Alice calls contract that attempts `EXTCODECOPY` from cold target contract. Parameterized: (1) OOG at EXTCODECOPY opcode (insufficient gas), (2) Successful EXTCODECOPY execution. | For OOG case: BAL **MUST NOT** include target contract (wasn't accessed). For success case: BAL **MUST** include target contract in `account_changes`. | ✅ Completed |
52+
| `test_bal_extcodecopy_and_oog` | Ensure BAL handles OOG during EXTCODECOPY at various failure points | Alice calls contract that attempts `EXTCODECOPY` from cold target contract. Parameterized: (1) Successful EXTCODECOPY, (2) OOG at cold access (insufficient gas for account access), (3) OOG at memory expansion with large offset (64KB offset, gas covers cold access + copy but NOT memory expansion), (4) OOG at memory expansion boundary (256 byte offset, gas is exactly 1 less than needed). | For success case: BAL **MUST** include target contract. For all OOG cases: BAL **MUST NOT** include target contract. Gas for ALL components (cold access + copy + memory expansion) must be checked BEFORE recording account access. | ✅ Completed |
5353
| `test_bal_oog_7702_delegated_cold_cold` | Ensure BAL handles OOG during EIP-7702 delegated account loading when both accounts are cold | Alice calls cold delegated account Bob (7702) which delegates to cold `TargetContract` with insufficient gas for second cold load | BAL **MUST** include Bob in `account_changes` (first cold load succeeds) but **MUST NOT** include `TargetContract` (second cold load fails due to OOG) | 🟡 Planned |
5454
| `test_bal_oog_7702_delegated_warm_cold` | Ensure BAL handles OOG during EIP-7702 delegated account loading when first account is warm, second is cold | Alice calls warm delegated account Bob (7702) which delegates to cold `TargetContract` with insufficient gas for second cold load | BAL **MUST** include Bob in `account_changes` (warm load succeeds) but **MUST NOT** include `TargetContract` (cold load fails due to OOG) | 🟡 Planned |
5555
| `test_bal_multiple_balance_changes_same_account` | Ensure BAL tracks multiple balance changes to same account across transactions | Alice funds Bob (starts at 0) in tx0 with exact amount needed. Bob spends everything in tx1 to Charlie. Bob's balance: 0 → funding_amount → 0 | BAL **MUST** include Bob with two `balance_changes`: one at txIndex=1 (receives funds) and one at txIndex=2 (balance returns to 0). This tests balance tracking across two transactions. | ✅ Completed |

0 commit comments

Comments
 (0)