Skip to content

Markdown Content

Below is the verbatim markdown content from tests/amsterdam/eip7928_block_level_access_lists/test_cases.md@b314d18e.

EIP-7928 Block Access Lists (BAL) Test Cases

Function Name Goal Setup Expectation Status
test_bal_nonce_changes Ensure BAL captures changes to nonce Alice sends 100 wei to Bob BAL MUST include changes to Alice's nonce. ✅ Completed
test_bal_balance_changes Ensure BAL captures changes to balance Alice sends 100 wei to Bob BAL MUST include balance change for Alice, Bob, and Coinbase ✅ Completed
test_bal_code_changes Ensure BAL captures changes to account code Alice deploys factory contract that creates new contract BAL MUST include code changes for newly deployed contract ✅ Completed
test_selfdestruct_to_account (TangerineWhistle) Ensure BAL captures SELFDESTRUCT success boundary for account beneficiaries Victim executes SELFDESTRUCT(beneficiary) at exact gas boundary. Tests final gas boundary where operation completes. Parametrized: is_success (exact_gas/exact_gas_minus_1), beneficiary (EOA/contract), warm (cold/warm where warm=Berlin+), same_tx (pre_deploy/same_tx), originator_balance (0/1), beneficiary_balance (0/1). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. exact_gas: Beneficiary in BAL with balance_changes, victim destroyed (pre-Cancun/same_tx) or preserved (>=Cancun). exact_gas_minus_1: OOG, beneficiary in BAL only if G_NEW_ACCOUNT was part of gas calculation. ✅ Completed
test_selfdestruct_state_access_boundary (TangerineWhistle) Ensure BAL correctly tracks beneficiary access at state access boundary (consensus check) Victim executes SELFDESTRUCT(beneficiary) at state access boundary (base + cold). Verifies beneficiary is accessed before G_NEW_ACCOUNT check. Parametrized: is_success (exact_gas/exact_gas_minus_1), beneficiary (EOA/contract), warm (cold/warm), same_tx, originator_balance (0/1), beneficiary_balance (0/1). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. exact_gas: Beneficiary IN BAL (state accessed). exact_gas_minus_1: Beneficiary NOT in BAL (OOG before state access). Operation may succeed at exact_gas if no G_NEW_ACCOUNT needed. ✅ Completed
test_selfdestruct_to_self (TangerineWhistle) Ensure BAL captures SELFDESTRUCT where beneficiary is self at gas boundary Victim executes SELFDESTRUCT(ADDRESS) - selfdestructs to itself. Always warm, always alive (no G_NEW_ACCOUNT, no cold access). Gas = G_BASE + G_SELF_DESTRUCT. Parametrized: is_success (exact_gas/exact_gas_minus_1), originator_balance (0/1), same_tx (pre_deploy/same_tx). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. exact_gas_minus_1: Victim in BAL with unchanged state. exact_gas: Pre-Cancun/same_tx: destroyed, balance=0. >=Cancun pre-existing: preserved with original balance. ✅ Completed
test_selfdestruct_to_precompile (TangerineWhistle) Ensure BAL captures SELFDESTRUCT success boundary for precompile beneficiaries Victim executes SELFDESTRUCT(precompile) at exact gas boundary. Precompiles are always warm (no cold access charge). Parametrized: is_success (exact_gas/exact_gas_minus_1), all precompiles via @pytest.mark.with_all_precompiles, same_tx (pre_deploy/same_tx), originator_balance (0/1), beneficiary_balance (0/1). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. exact_gas: Precompile in BAL with balance_changes, victim destroyed (pre-Cancun/same_tx) or preserved (>=Cancun). exact_gas_minus_1: OOG, precompile in BAL only if G_NEW_ACCOUNT was part of gas calculation. ✅ Completed
test_selfdestruct_to_precompile_state_access_boundary (TangerineWhistle) Ensure BAL correctly tracks precompile access at state access boundary (consensus check) Victim executes SELFDESTRUCT(precompile) at state access boundary (base only, precompiles always warm). Verifies precompile is accessed before G_NEW_ACCOUNT check. Parametrized: is_success (exact_gas/exact_gas_minus_1), all precompiles, same_tx, originator_balance (0/1), beneficiary_balance (0/1). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. exact_gas: Precompile IN BAL (state accessed). exact_gas_minus_1: Precompile NOT in BAL (OOG before state access). Operation may succeed at exact_gas if no G_NEW_ACCOUNT needed. ✅ Completed
test_selfdestruct_to_system_contract (Cancun) Ensure BAL captures SELFDESTRUCT success boundary for system contract beneficiaries Victim executes SELFDESTRUCT(system_contract) at exact gas boundary. System contracts are always warm (no cold access charge) and always have code (no G_NEW_ACCOUNT charge). Gas = G_VERY_LOW + G_SELF_DESTRUCT. Parametrized: is_success (exact_gas/exact_gas_minus_1), all system contracts via @pytest.mark.with_all_system_contracts, same_tx (pre_deploy/same_tx), originator_balance (0/1). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. exact_gas: System contract in BAL with balance_changes if originator had balance, victim destroyed (same_tx) or balance=0 (pre-existing). exact_gas_minus_1: OOG, system contract not in BAL (no state access). ✅ Completed
test_initcode_selfdestruct_to_self (TangerineWhistle) Ensure BAL captures SELFDESTRUCT during initcode where beneficiary is self Initcode executes SELFDESTRUCT(ADDRESS) during CREATE, before any code is deployed. Contract has nonce=1 (post-EIP-161), making it non-empty. Always warm (executing contract), no G_NEW_ACCOUNT (nonce > 0). Gas boundary testing not possible (CREATE uses all available gas). Parametrized: originator_balance (0/1). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. Contract created and destroyed in same tx - victim has empty BAL changes. Caller has nonce_changes (incremented by CREATE) and balance_changes if originator had balance. Victim is NONEXISTENT in post state. ✅ Completed
test_bal_account_access_target Ensure BAL captures target addresses of account access opcodes Alice calls Oracle contract which uses account access opcodes (BALANCE, EXTCODESIZE, EXTCODECOPY, EXTCODEHASH, CALL, CALLCODE, DELEGATECALL, STATICCALL) on TargetContract. BAL MUST include Alice, Oracle, and TargetContract with empty changes for TargetContract and nonce changes for Alice. ✅ Completed
test_bal_call_no_delegation_and_oog_before_target_access Ensure BAL handles OOG before target access and success for non-delegated CALL Parametrized: target warm/cold, target empty/existing, value 0/1, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/success). OOG: target in BAL ONLY if pre-warmed. Success: target always in BAL with balance changes when value > 0. ✅ Completed
test_bal_call_no_delegation_oog_after_target_access Ensure BAL includes target but excludes value transfer when OOG after target access Hardcoded: empty target, value=1 (required for create_cost gap). Parametrized: warm/cold, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910). Target always in BAL. No balance changes (value transfer fails after G_NEW_ACCOUNT check). ✅ Completed
test_bal_call_7702_delegation_and_oog Ensure BAL handles OOG at all 4 boundaries for CALL to 7702 delegated accounts Parametrized: target warm/cold, delegation warm/cold, value 0/1, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/after_target_access/success_minus_1/success). OOG before: neither in BAL. OOG after & success_minus_1: target in BAL, delegation NOT in BAL (static check optimization). Success: all in BAL. ✅ Completed
test_bal_callcode_nested_value_transfer Ensure BAL captures balance changes from nested value transfers when CALLCODE executes target code that itself makes CALL with value Alice calls Oracle contract (200 wei balance) which uses CALLCODE to execute TargetContract's code; that code makes a nested CALL transferring 100 wei to Bob. BAL MUST include Alice (nonce changes), Oracle (balance change to 100 wei), Bob (balance change to 100 wei), and TargetContract (empty changes). ✅ Completed
test_bal_delegated_storage_writes Ensure BAL captures delegated storage writes via DELEGATECALL and CALLCODE Alice calls Oracle contract which uses DELEGATECALL/CALLCODE to TargetContract that writes 0x42 to slot 0x01. BAL MUST include Alice (nonce changes), Oracle (storage changes for slot 0x01 = 0x42), and TargetContract (empty changes). ✅ Completed
test_bal_delegated_storage_reads Ensure BAL captures delegated storage reads via DELEGATECALL and CALLCODE Alice calls Oracle contract (with slot 0x01 = 0x42) which uses DELEGATECALL/CALLCODE to TargetContract that reads from slot 0x01. BAL MUST include Alice (nonce changes), Oracle (storage reads for slot 0x01), and TargetContract (empty changes). ✅ Completed
test_bal_block_rewards BAL tracks fee recipient balance changes from block rewards Alice sends 100 wei to Bob with Charlie as fee recipient BAL MUST include fee recipient Charlie with balance_changes reflecting transaction fees collected from the block. ✅ Completed
test_bal_selfdestruct_to_coinbase Ensure BAL records SELFDESTRUCT when the beneficiary is the coinbase address. Parametrized over same_tx ∈ [False, True]. Coinbase pre-funded with amount=0 (empty per EIP-161). gas_price = base_fee_per_gas so the priority-fee tip is zero and coinbase's entry carries only the SELFDESTRUCT transfer. pre_deploy: pre-existing victim contract (balance 100) executes SELFDESTRUCT(Op.COINBASE); post-Cancun (EIP-6780) the contract is preserved with balance 0. same_tx: factory creates victim with CREATE(value=100, ...) and CALLs it; victim's runtime SELFDESTRUCT runs in the same tx so the contract is actually destroyed. pre_deploy: BAL MUST include victim with balance_changes 100→0 and coinbase with balance_changes 0→100. same_tx: BAL MUST include factory with nonce_changes (CREATE bumped nonce) + balance_changes 100→0, victim with empty changes (created+destroyed same-tx), and coinbase with balance_changes 0→100. ✅ Completed
test_bal_2930_account_listed_but_untouched Ensure BAL excludes listed but untouched account Alice sends a simple eth transfer tx to Bob with EIP-2930 access list including Oracle BAL MUST NOT include any entry for Oracle because it wasn't accessed. ✅ Completed
test_bal_2930_slot_listed_but_untouched Ensure BAL excludes listed but untouched storage slots Alice sends tx with EIP-2930 access list including (PureCalculator, slot=0x01); PureCalculator executes pure arithmetic (adding two numbers) without touching slot 0x01 BAL MUST NOT include any entry for PureCalculator's slot 0x01 because it doesn't access state ✅ Completed
test_bal_2930_slot_listed_and_unlisted_writes Ensure BAL includes storage writes regardless of access list presence Alice sends tx with EIP-2930 access list including (StorageWriter, slot=0x01); StorageWriter executes SSTORE to slots 0x01 and 0x02 BAL MUST include storage_changes for StorageWriter's slots 0x01 and 0x02 ✅ Completed
test_bal_2930_slot_listed_and_unlisted_reads Ensure BAL includes storage reads regardless of access list presence Alice sends tx with EIP-2930 access list including (StorageReader, slot=0x01); StorageReader executes SLOAD from slots 0x01 and 0x02 BAL MUST include storage_reads for StorageReader's slots 0x01 and 0x02 ✅ Completed
test_bal_self_transfer BAL handles self-transfers correctly Alice sends 100 wei to Alice BAL MUST include one entry for Alice with balance_changes reflecting gas cost only (value cancels out) and nonce change. ✅ Completed
test_bal_zero_value_transfer BAL handles zero-value transfers correctly Alice sends 0 wei to Bob BAL MUST include Alice with balance_changes (gas cost only) and nonce change, and Bob in account_changes with empty balance_changes. ✅ Completed
test_bal_noop_storage_write Ensure BAL includes storage read but not write for no-op writes where pre-state equals post-state Contract with pre-existing storage value 0x42 in slot 0x01; transaction executes SSTORE(0x01, 0x42) (writing same value) BAL MUST include the contract address with storage_reads for slot 0x01 since it was accessed, but MUST NOT include it in storage_changes (no actual state change). ✅ Completed
test_bal_fully_unmutated_account Ensure BAL captures account that has zero net mutations Alice sends 0 wei to Oracle which writes same pre-existing value to storage BAL MUST include Alice with nonce_changes and balance changes (gas), Oracle with storage_reads for accessed slot but empty storage_changes. ✅ Completed
test_bal_net_zero_balance_transfer BAL includes accounts with net-zero balance change but excludes them from balance changes Contract receives and sends same amount to recipient using CALL or SELFDESTRUCT BAL MUST include contract in account_changes without balance_changes (net zero). BAL MUST record non-zero balance_changes for recipient. ✅ Completed
test_bal_system_dequeue_consolidations_eip7251 BAL tracks post-exec system dequeues for consolidations Pre-populate EIP-7251 consolidation requests; produce a block where dequeues occur BAL MUST include the 7251 system contract with storage_changes (queue slots 0–3) using block_access_index = len(txs). ✅ Completed
test_bal_withdrawal_contract_cross_index Ensure withdrawal system contract shows storage changes at both tx and post-execution indices Alice sends withdrawal request to EIP-7002 system contract. Slots 0x01 (count) and 0x03 (tail) are incremented during tx (index 1) and reset during post-execution dequeue (index 2). BAL MUST include withdrawal request contract with storage_changes for slots 0x01 and 0x03, each with two slot_changes: one at block_access_index=1 (tx) and one at block_access_index=2 (post-exec). ✅ Completed
test_bal_consolidation_contract_cross_index Ensure consolidation system contract shows storage changes at both tx and post-execution indices Alice sends consolidation request to EIP-7251 system contract. Slots 0x01 (count) and 0x03 (tail) are incremented during tx (index 1) and reset during post-execution dequeue (index 2). BAL MUST include consolidation request contract with storage_changes for slots 0x01 and 0x03, each with two slot_changes: one at block_access_index=1 (tx) and one at block_access_index=2 (post-exec). ✅ Completed
test_bal_noop_write_filtering Ensure BAL filters NOOP storage writes (writing same value or 0 to empty slot) Contract writes 0 to uninitialized slot 1 (noop), 42 to slot 2 (real change), 100 to slot 3 (same as pre-state, noop), 200 to slot 4 (different from pre-state 150, real change). BAL MUST include storage_changes only for slots 2 and 4 (actual changes). Slots 1 and 3 MUST NOT appear in storage_changes (no-op writes filtered). ✅ Completed
test_bal_system_contract_noop_filtering Ensure system contract post-execution calls filter net-zero storage writes Simple transfer that doesn't interact with system contracts. Post-execution system calls read withdrawal/consolidation contract slots 0-3 but don't modify them. Withdrawal and consolidation system contracts MUST have storage_reads for slots 0x00-0x03 but MUST NOT have storage_changes (no actual modifications occurred). ✅ Completed
test_bal_aborted_storage_access Ensure BAL captures storage access in aborted transactions correctly Alice calls contract that reads storage slot 0x01, writes to slot 0x02, then aborts with REVERT/INVALID BAL MUST include storage_reads for slots 0x01 and 0x02 (aborted writes become reads), empty storage_changes. Only nonce changes for Alice. ✅ Completed
test_bal_aborted_account_access Ensure BAL captures account access in aborted transactions for all account accessing opcodes Alice calls AbortContract that performs account access operations (BALANCE, EXTCODESIZE, EXTCODECOPY, EXTCODEHASH, CALL, CALLCODE, DELEGATECALL, STATICCALL) on TargetContract and aborts via REVERT/INVALID BAL MUST include Alice, TargetContract, and AbortContract in account_changes and nonce changes for Alice. ✅ Completed
test_bal_parent_revert_state_access Ensure BAL captures child-frame state access when the parent frame reverts (write-demoted-to-read across frame boundary). Parametrized: inner_action ∈ [sstore, sload, balance, extcodesize], outer_abort ∈ [REVERT, INVALID]. Outer contract CALLs an inner contract that performs one state-access op (SSTORE/SLOAD against its own storage, or BALANCE/EXTCODESIZE against a separate target). Inner's slot 1 is pre-set to 0xDEAD so the post-state confirms the demoted SSTORE didn't overwrite it. Inner returns successfully; outer then aborts. BAL MUST include inner with storage_reads=[1] (SSTORE/SLOAD cases — write demoted to read), or empty changes plus the separate target in BAL with empty changes (BALANCE/EXTCODESIZE cases). Post-state: inner.storage[1] == 0xDEAD for SSTORE/SLOAD cases. ✅ Completed
test_selfdestruct_balance_transfer_reverted (Cancun) Ensure BAL records SELFDESTRUCT touches even when the containing sub-call reverts. Multi-fork via state_test; BAL expectations gated on fork.is_eip_enabled(7928). File: tests/cancun/eip6780_selfdestruct/test_journal_revert.py. Outer → controller (CALL) → victim (CALL); victim executes SELFDESTRUCT(beneficiary), controller REVERTs (rolling back the balance transfer), outer continues and observes balances. When EIP-7928 is enabled, BAL MUST include victim and beneficiary with empty changes (touched in the reverted sub-call's SELFDESTRUCT plus outer's BALANCE reads; net balances unchanged). ✅ Completed
test_bal_outer_revert_with_inner_insufficient_funds Combine outer-frame REVERT with inner-frame insufficient-funds CALL or CREATE. Parametrized inner_op ∈ [call, create]. Outer → inner (CALL). Inner does SSTORE(slot_a, 0x42), then attempts CALL/CREATE with value > balance=0. Inner returns successfully (insufficient-balance check happens after the opcode's state-touching costs are charged, not via a REVERT). Outer then REVERTs. Inner's two SSTOREs demote to storage_reads. For call: the failed call's target appears in BAL with empty changes (cold access charged before balance check). For create: the would-be address is NOT in BAL (early failure precedes track_address). ✅ Completed
test_create_insufficient_balance (Berlin) Ensure BAL records that a failed CREATE does NOT itself add the would-be address; only a subsequent BALANCE call does. Multi-fork via state_test; BAL gated on fork.is_eip_enabled(7928). File: tests/berlin/eip2929_gas_cost_increases/test_create.py. Entry → creator (CREATE with value=1, creator balance 0 → fails) → checker (cold BALANCE on the would-be address, measures gas). Creator has real storage_changes (slot 0 = 1 → 0). Checker has storage_changes (slot 1 = cold BALANCE gas cost). Would-be address appears in BAL with empty changes — accessed only via the BALANCE in the checker contract, NOT via the failed CREATE. ✅ Completed
test_bal_pure_contract_call Ensure BAL captures contract access for pure computation calls Alice calls PureContract that performs pure arithmetic (ADD operation) without storage or balance changes BAL MUST include Alice and PureContract in account_changes, and nonce_changes for Alice. ✅ Completed
test_bal_create_storage_op_then_selfdestruct_same_tx BAL correctly demotes ephemeral storage operations to storage_reads when a contract is created and destroyed in the same tx (combined coverage for read and write storage_op cases — replaces test_bal_create2_to_A_read_then_selfdestruct and test_bal_create2_to_A_write_then_selfdestruct). Parametrized: @pytest.mark.with_all_create_opcodes + storage_op ∈ ["read", "write"]. Address A is pre-funded via pre.fund_address. Alice sends a single tx calling a factory that deploys a contract at A via the parametrized create opcode; init code is either SLOAD(B)+SELFDESTRUCT or SSTORE(B, v)+SELFDESTRUCT (beneficiary = separate EOA). BAL MUST include A with balance_changes [(1, 0)] (outflow to beneficiary on destruction). Slot B MUST appear under storage_reads, NOT storage_changes (write demoted to read because the contract is destroyed same-tx). A MUST NOT have nonce_changes or code_changes. Beneficiary has balance_changes reflecting receipt of fund at index 1. ✅ Completed
test_bal_precompile_funded BAL records precompile value transfer with or without balance change Alice sends value to precompile (all precompiles) via direct transaction. Parameterized: (1) with value (1 ETH), (2) without value (0 ETH). For with_value: BAL MUST include precompile with balance_changes. For no_value: BAL MUST include precompile with empty balance_changes. No storage_changes or code_changes in either case. ✅ Completed
test_bal_precompile_call_opcode BAL records the precompile address regardless of call opcode. Parametrized: @pytest.mark.with_all_precompiles × @pytest.mark.with_all_call_opcodes. Alice calls Oracle which invokes the precompile via the parametrized call opcode. For DELEGATECALL/CALLCODE the precompile provides the code but is not the call target, so its access has to be recorded explicitly rather than incidentally. BAL MUST include the precompile address with empty changes for all four call opcodes. Oracle has empty changes (called but no state mutation), Alice has nonce_changes. ✅ Completed
test_bal_7702_delegated_create BAL tracks EIP-7702 delegation indicator write and contract creation Alice sends a type-4 (7702) tx authorizing herself to delegate to Deployer code which executes CREATE BAL MUST include for Alice: code_changes (delegation indicator), nonce_changes (increment from 7702 processing), and balance_changes (post-gas). For Child: code_changes (runtime bytecode) and nonce_changes = 1. ✅ Completed
test_bal_7702_delegation_create Ensure BAL captures creation of EOA delegation Alice authorizes delegation to contract Oracle. Transaction sends 10 wei to Bob. Two variants: (1) Self-funded: Alice sends 7702 tx herself. (2) Sponsored: Relayer sends 7702 tx on Alice's behalf. BAL MUST include Alice: code_changes (delegation designation 0xef0100\|\|address(Oracle)),nonce_changes (increment). Bob: balance_changes (receives 10 wei). For sponsored variant, BAL MUST also include Relayer:nonce_changes.Oracle MUST NOT be present in BAL - the account is never accessed. ✅ Completed
test_bal_7702_delegation_update Ensure BAL captures update of existing EOA delegation. Three variants: (1) Self-funded: Alice sends both 7702 txs herself. (2) Sponsored: a single Relayer sends both txs on Alice's behalf. (3) sponsored_cross_sender: a distinct relayer per tx — exercises the cross-tx auth-nonce-chain dependency since sender-nonce serialization no longer trivializes the test. A client that parallel-verifies auth signatures must consult Alice's BAL nonce_changes to validate the second auth against her post-tx-1 nonce. Alice first delegates to Oracle1, then in second tx updates delegation to Oracle2. Each transaction sends 10 wei to Bob. BAL MUST include Alice: first tx has code_changes (delegation designation 0xef0100\|\|address(Oracle1)),nonce_changes. Second tx hascode_changes (delegation designation 0xef0100\|\|address(Oracle2)),nonce_changes. Bob:balance_changes (receives 10 wei on each tx). For sponsored variant, BAL MUST also include Relayer:nonce_changes for both transactions; for sponsored_cross_sender, each relayer has one nonce_changes at its tx index. Oracle1 and Oracle2 MUST NOT be present in BAL - accounts are never accessed. ✅ Completed
test_bal_7702_delegation_clear Ensure BAL captures clearing of EOA delegation Alice first delegates to Oracle, then in second tx clears delegation by authorizing to 0x0 address. Each transaction sends 10 wei to Bob. Two variants: (1) Self-funded: Alice sends both 7702 txs herself. (2) Sponsored: Relayer sends both 7702 txs on Alice's behalf. BAL MUST include Alice: first tx has code_changes (delegation designation 0xef0100\|\|address(Oracle)), nonce_changes. Second tx has code_changes (empty code - delegation cleared), nonce_changes. Bob: balance_changes (receives 10 wei on each tx). For sponsored variant, BAL MUST also include Relayer: nonce_changes for both transactions. Oracle and 0x0 address MUST NOT be present in BAL - accounts are never accessed. ✅ Completed
test_bal_7702_delegated_storage_access Ensure BAL captures storage operations when calling a delegated EIP-7702 account Alice has delegated her account to Oracle. Oracle contract contains code that reads from storage slot 0x01 and writes to storage slot 0x02. Bob sends 10 wei to Alice (the delegated account), which executes Oracle's code. BAL MUST include Alice: balance_changes (receives 10 wei), storage_changes for slot 0x02 (write operation performed in Alice's storage), storage_reads for slot 0x01 (read operation from Alice's storage). Bob: nonce_changes (sender), balance_changes (loses 10 wei plus gas costs). Oracle (account access). ✅ Completed
test_bal_7702_invalid_nonce_authorization Ensure BAL handles failed authorization due to wrong nonce Relayer sends sponsored transaction to Bob (10 wei transfer succeeds) but Alice's authorization to delegate to Oracle uses incorrect nonce, causing silent authorization failure BAL MUST include Alice with empty changes (account access), Bob with balance_changes (receives 10 wei), Relayer with nonce_changes. MUST NOT include Oracle (authorization failed, no delegation) ✅ Completed
test_bal_7702_invalid_chain_id_authorization Ensure BAL handles failed authorization due to wrong chain id Relayer sends sponsored transaction to Bob (10 wei transfer succeeds) but Alice's authorization to delegate to Oracle uses incorrect chain id, causing authorization failure before account access BAL MUST include Bob with balance_changes (receives 10 wei), Relayer with nonce_changes. MUST NOT include Alice (authorization fails before loading account) or Oracle (authorization failed, no delegation) ✅ Completed
test_call_into_self_delegating_set_code Self-delegation degenerate one-hop case (companion to test_call_into_chain_delegating_set_code). File: tests/prague/eip7702_set_code_tx/test_set_code_txs.py. Parametrized over @pytest.mark.with_all_call_opcodes. auth_signer auths itself as its own delegation target. entry_address issues call_opcode(auth_signer). EVM resolves once: auth_signer's code is the designator pointing back to auth_signer; the second hop is not followed, so the 0xef0100... bytecode runs as legacy code → INVALID → returns 0. auth_signer MUST appear with nonce_changes and code_changes (delegation designator to itself). entry_address MUST have storage_reads=[0] (no-op SSTORE demoted). No additional delegation-target entry is created because the target coincides with the authority. ✅ Completed
test_bal_7702_invalid_authority_has_code_authorization Ensure BAL handles failed authorization where the authority already has non-empty, non-delegation code (EIP-7702 step-5 rejection, post-load). Alice is pre-allocated with code=Op.STOP and nonce=1. Relayer sends sponsored tx to Bob (10 wei transfer). Authorization tuple delegates Alice to Oracle with matching nonce. EIP-7702 step 5 rejects because Alice's code is non-empty and not a delegation designator. BAL MUST include Bob with balance_changes (10 wei), Relayer with nonce_changes, and Alice with empty changes (loaded at step 4 then rejected at step 5). MUST NOT include Oracle (delegation target never loaded). ✅ Completed
test_signature_s_out_of_range Ensure BAL excludes the authority when the EIP-7702 auth signature has an out-of-range s value (EIP-2 low-s rule, ecrecover fails before authority is loaded). File: tests/prague/eip7702_set_code_tx/test_set_code_txs.py. auth_signer signs a normal auth tuple delegating to set_code_to_address; the tuple is then mutated so s = SECP256K1N - s and v is flipped, producing a high-s signature. Sender (a separate EOA) sends the tx to entry_address which executes SSTORE(1, 1). BAL MUST include sender with nonce_changes at block_access_index=1 and entry_address with storage_changes for slot 1 (post=1). BAL MUST NOT include auth_signer (auth fails at ecrecover, before the authority is added to accessed_addresses) or set_code_to_address (target is never loaded as an execution target). ✅ Completed
test_nonce_validity Ensure BAL correctly records EIP-7702 auth-tuple nonce-field validity across pre-load (nonce >= 2**64-1), success, and post-load (account.nonce != auth.nonce) branches. File: tests/prague/eip7702_set_code_tx/test_set_code_txs.py. Parametrized over (account_nonce, authorization_nonce): (1) (MAX, MAX) pre-load rejection at step 2, (2) (MAX-1, MAX-1) successful auth, (3) (0, 1) post-load nonce mismatch, (4) (1, 0) post-load nonce mismatch. entry_address always does SSTORE(success_slot, 1) + CALL(auth_signer) + SSTORE(return_slot, RETURNDATASIZE). Valid auth (case 2): auth_signer MUST have nonce_changes (post=account_nonce+1) and code_changes (delegation designation); set_code_to_address MUST appear with empty changes (loaded as execution target via delegation dispatch); entry_address has storage_changes for both slot 1 and slot 2 (post=1). Invalid auth (cases 1, 3, 4): auth_signer MUST appear with empty changes (the subsequent CALL touches it, even though the auth processing did or did not add it); set_code_to_address MUST NOT be in BAL; entry_address has storage_changes for slot 1 and storage_reads for slot 2 (the SSTORE(0, 0) no-op is demoted per EIP-7928). Sender always has nonce_changes. ✅ Completed
test_call_into_chain_delegating_set_code Ensure BAL respects EIP-7702 one-hop delegation resolution when A delegates to B and B delegates back to A. File: tests/prague/eip7702_set_code_tx/test_set_code_txs.py. Parameterized over @pytest.mark.with_all_call_opcodes. Two auths: auth_signer_1 -> auth_signer_2, then auth_signer_2 -> auth_signer_1. entry_address issues call_opcode(auth_signer_1) and stores the return code in slot 0. The EVM resolves A -> B once, then runs B's 0xef0100... bytecode as legacy code; 0xef is INVALID, so the call frame aborts and returns 0. BAL MUST include only auth_signer_1 and auth_signer_2 from the delegation chain (each with nonce_changes and code_changes for its delegation designator). No third address is ever loaded because the second hop is never followed. entry_address MUST have storage_reads for slot 0 (the SSTORE(slot, 0) is a no-op write and is demoted per EIP-7928) and no storage_changes. Sender has nonce_changes. ✅ Completed
test_bal_7702_multi_hop_delegation_chain Multi-hop EIP-7702 delegation: chain resolves A→B→C and loop resolves A→B→A. In both cases the EVM follows the delegation once and runs B's 0xef0100<dest> bytecode, which aborts on the INVALID 0xef opcode. Parametrized over destination_is_loop ∈ [False, True]. auth_a delegates to auth_b; auth_b delegates to either target_c (chain) or back to auth_a (loop). Entry contract has storage[0] = 0xDEAD (witness) and issues CALL(auth_a) then stores the return code in slot 0. auth_a and auth_b MUST appear with nonce_changes and code_changes (each successful auth). In chain, target_c MUST NOT appear in BAL. entry_address has storage_changes for slot 0 with post_value=0 (0xDEAD overwritten by the failed CALL's return code 0). Sender has nonce_changes. ✅ Completed
test_set_code_to_precompile Covers the BAL recording of a precompile address when reached via EIP-7702 delegation dispatch — across all 4 call opcodes and all precompiles. Companion to test_bal_precompile_call_opcode for the direct-call path. File: tests/prague/eip7702_set_code_tx/test_set_code_txs.py. @pytest.mark.with_all_call_opcodes × @pytest.mark.with_all_precompiles. EOA auth_signer delegates to a precompile address. A caller contract invokes call_opcode(auth_signer); EIP-7702 resolves the delegation to the precompile (whose code is treated as empty per spec). When EIP-7928 is enabled, BAL MUST include auth_signer with nonce_changes and code_changes (delegation designator), and MUST include the precompile address with empty changes (loaded as execution target via delegation dispatch). ✅ Completed
test_bal_7702_delegated_via_call_opcode Ensure BAL captures delegation target when a contract uses *CALL opcodes to call a delegated account Pre-deployed contract Alice delegated to Oracle. Caller contract uses CALL/CALLCODE/DELEGATECALL/STATICCALL to call Alice. Bob sends transaction to Caller. BAL MUST include Bob: nonce_changes. Caller: empty changes (account access). Alice: empty changes (account access - delegated account being called). Oracle: empty changes (delegation target access). ✅ Completed
test_bal_7702_null_address_delegation_no_code_change Ensure BAL does not record spurious code changes for net-zero code operations Alice sends transaction with authorization delegating to NULL_ADDRESS (0x0), which sets code to b"" on an account that already has b"" code. Transaction sends 10 wei to Bob. BAL MUST include Alice with nonce_changes (tx nonce + auth nonce increment) but MUST NOT include code_changes (setting b"" -> b"" is net-zero and filtered out). Bob: balance_changes (receives 10 wei). This ensures net-zero code change is not recorded. ✅ Completed
test_bal_7702_double_auth_reset Ensure BAL tracks multiple 7702 nonce increments but filters net-zero code change Single transaction contains two EIP-7702 authorizations for Alice: (1) first auth sets delegation 0xef0100\|\|Oracle, (2) second auth clears delegation back to empty. Transaction sends 10 wei to Bob. Two variants: (a) Self-funded: Alice is tx sender (one tx nonce bump + two auth bumps → nonce 0→3). (b) Sponsored: Relayer is tx sender (Alice only in auths → nonce 0→2 for Alice, plus one nonce bump for Relayer). Variant (a): BAL MUST include Alice with nonce_changes 0→3. Variant (b): BAL MUST include Alice with nonce_changes 0→2 and Relayer with its own nonce_changes. For both variants, BAL MUST NOT include code_changes for Alice (net code is empty), MUST include Bob with balance_changes (receives 10 wei), and Oracle MUST NOT appear in BAL. ✅ Completed
test_bal_7702_double_auth_swap Ensure BAL captures final code when double auth swaps delegation targets Relayer sends transaction with two authorizations for Alice: (1) First auth sets delegation to CONTRACT_A at nonce=0, (2) Second auth changes delegation to CONTRACT_B at nonce=1. Transaction sends 10 wei to Bob. Per EIP-7702, only the last authorization takes effect. BAL MUST include Alice with nonce_changes (both auths increment nonce to 2) and code_changes (final code is delegation designation for CONTRACT_B, not CONTRACT_A). Bob: balance_changes (receives 10 wei). Relayer: nonce_changes. Neither CONTRACT_A nor CONTRACT_B appear in BAL during delegation setup (never accessed). This ensures BAL shows final state, not intermediate changes. ✅ Completed
test_bal_sstore_and_oog Ensure BAL handles OOG during SSTORE execution at various gas boundaries (EIP-2200 stipend and implicit SLOAD) Alice calls contract that attempts SSTORE to cold slot 0x01. Parameterized: (1) OOG at EIP-2200 stipend check (2300 gas after PUSH opcodes) - fails before implicit SLOAD, (2) OOG at stipend + 1 (2301 gas) - passes stipend check but fails after implicit SLOAD, (3) OOG at exact gas - 1, (4) Successful SSTORE with exact gas. For case (1): BAL MUST NOT include slot 0x01 in storage_reads or storage_changes (fails before implicit SLOAD). For cases (2) and (3): BAL MUST include slot 0x01 in storage_reads (implicit SLOAD occurred) but MUST NOT include in storage_changes (write didn't complete). For case (4): BAL MUST include slot 0x01 in storage_changes only (successful write; read is filtered by builder). ✅ Completed
test_bal_sstore_static_context SSTORE in static context must not leak storage reads into BAL Contract A STATICCALLs Contract B which attempts SSTORE. Parametrized: original_value (0, nonzero) to catch clients that perform the implicit SLOAD before the static check. Contract B IS in BAL (accessed via STATICCALL) but MUST NOT have storage_reads. ✅ Completed
test_bal_sload_and_oog Ensure BAL handles OOG during SLOAD execution correctly Alice calls contract that attempts SLOAD from cold slot 0x01. Parameterized: (1) OOG at SLOAD opcode (insufficient gas), (2) Successful SLOAD execution. For OOG case: BAL MUST NOT contain slot 0x01 in storage_reads since storage wasn't accessed. For success case: BAL MUST contain slot 0x01 in storage_reads. ✅ Completed
test_bal_balance_and_oog Ensure BAL handles OOG during BALANCE opcode execution correctly Alice calls contract that attempts BALANCE opcode on cold target account. Parameterized: (1) OOG at BALANCE opcode (insufficient gas), (2) Successful BALANCE execution. For OOG case: BAL MUST NOT include target account (wasn't accessed). For success case: BAL MUST include target account in account_changes. ✅ Completed
test_bal_account_touch_system_address Ensure BAL includes SYSTEM_ADDRESS when a regular transaction touches it via any account-accessing opcode Alice calls a contract that executes one of BALANCE, EXTCODESIZE, EXTCODEHASH, EXTCODECOPY, CALL, or STATICCALL against SYSTEM_ADDRESS. Parametrized over the six opcodes. BAL MUST include SYSTEM_ADDRESS as an account-only entry for every opcode because the address experienced a real EVM state access. This is distinct from excluding the synthetic system-operation caller. ✅ Completed
test_bal_selfdestruct_to_system_address_zero_balance Ensure BAL includes SYSTEM_ADDRESS as the SELFDESTRUCT beneficiary even when no value is transferred. Companion to test_bal_account_touch_system_address (which covers BALANCE/EXTCODE*/CALL/STATICCALL); SELFDESTRUCT is the missing opcode in that parametrize list. File: tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_opcodes.py. CREATE transaction whose init code is SELFDESTRUCT(SYSTEM_ADDRESS); the new contract carries no value, so the beneficiary receives 0 wei. Per EIP-6780 the contract is deleted (creation and destruction in the same tx). BAL MUST include SYSTEM_ADDRESS with every change-set empty — the SELFDESTRUCT is the only access on SYSTEM_ADDRESS in this block. Post-state: created contract is NONEXISTENT (proves SELFDESTRUCT fired); Alice has nonce=1. ✅ Completed
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
test_bal_delegatecall_no_delegation_and_oog_before_target_access Ensure BAL handles OOG before target access and success for non-delegated DELEGATECALL Parametrized: target warm/cold, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/success). OOG: target in BAL ONLY if pre-warmed. Success: target always in BAL. ✅ Completed
test_bal_delegatecall_7702_delegation_and_oog Ensure BAL handles OOG at all 4 boundaries for DELEGATECALL to 7702 delegated accounts Parametrized: target warm/cold, delegation warm/cold, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/after_target_access/success_minus_1/success). OOG before: neither in BAL. OOG after & success_minus_1: target in BAL, delegation NOT in BAL (static check optimization). Success: all in BAL. ✅ Completed
test_bal_callcode_no_delegation_and_oog_before_target_access Ensure BAL handles OOG before target access and success for non-delegated CALLCODE Parametrized: target warm/cold, value 0/1, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/success). OOG: target in BAL ONLY if pre-warmed. Success: target always in BAL. ✅ Completed
test_bal_callcode_7702_delegation_and_oog Ensure BAL handles OOG at all 4 boundaries for CALLCODE to 7702 delegated accounts Parametrized: target warm/cold, delegation warm/cold, value 0/1, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/after_target_access/success_minus_1/success). OOG before: neither in BAL. OOG after & success_minus_1: target in BAL, delegation NOT in BAL (static check optimization). Success: all in BAL. ✅ Completed
test_bal_staticcall_no_delegation_and_oog_before_target_access Ensure BAL handles OOG before target access and success for non-delegated STATICCALL Parametrized: target warm/cold, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/success). OOG: target in BAL ONLY if pre-warmed. Success: target always in BAL. ✅ Completed
test_bal_staticcall_7702_delegation_and_oog Ensure BAL handles OOG at all 4 boundaries for STATICCALL to 7702 delegated accounts Parametrized: target warm/cold, delegation warm/cold, (args_size, ret_size) pair (covers in-only and out-only expansion per #1910), OOG boundary (before_target_access/after_target_access/success_minus_1/success). OOG before: neither in BAL. OOG after & success_minus_1: target in BAL, delegation NOT in BAL (static check optimization). Success: all in BAL. ✅ Completed
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
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
test_bal_multiple_storage_writes_same_slot Ensure BAL tracks multiple writes to same storage slot across transactions Alice calls contract 3 times in same block. Contract increments slot 1 on each call: 0 → 1 → 2 → 3 BAL MUST include contract with slot 1 having three slot_changes: txIndex=1 (value 1), txIndex=2 (value 2), txIndex=3 (value 3). Each transaction's write must be recorded separately. ✅ Completed
test_bal_nested_delegatecall_storage_writes_net_zero Ensure BAL correctly filters net-zero storage changes across nested DELEGATECALL frames Parametrized by nesting depth (1-3). Root contract has slot 0 = 1. Each frame writes a different intermediate value via DELEGATECALL chain, deepest frame writes back to original value (1). Example depth=2: 1 → 2 → 3 → 1 BAL MUST include root contract with storage_reads for slot 0 but MUST NOT include storage_changes (net-zero). All delegate contracts MUST have empty changes. Tests that frame merging correctly removes parent's intermediate writes when child reverts to pre-tx value. ✅ Completed
test_bal_cross_tx_storage_write Ensure storage changes behave as expected across transaction boundaries Tx1 writes a non-zero value to an empty slot; tx2 either writes zero (back to pre-block) or rewrites the same value (no-op vs post-tx1). Tx1's change always appears at index 1. The revert case adds tx2's change at index 2 (must not be filtered as net-zero). The same-value case adds nothing and the slot MUST NOT appear in storage_reads (uniqueness rule). ✅ Completed
test_bal_cross_tx_storage_chain Verify clients apply BAL state changes from prior transactions before executing later transactions in the same block. Each later Tx depends on the two preceding writes (Fibonacci-style), so any tx skipped or run against pre-block state cascades into a wrong slot value and a different state root. Fixed chain_length=8. Single branching contract: Tx i with i<2 seeds slot i with 1; Tx i with i>=2 writes slot[i] = SLOAD(i-1) + SLOAD(i-2). BAL MUST include the contract with storage_changes for each slot i (post=fib(i) at block_access_index=i+1). Post-state: slots 0-7 equal [1, 1, 2, 3, 5, 8, 13, 21]. ✅ Completed
test_bal_cross_tx_deploy_then_call Verify clients apply Tx1's CREATE to their state view before executing Tx2's CALL in the same block. A client that parallelizes Tx2 without applying Tx1's code_changes would hit an empty account, the CALL would no-op, and slot 0 would remain 0. Parametrized over @pytest.mark.with_all_create_opcodes (CREATE and CREATE2). Tx1 (Alice) calls a factory which CREATE/CREATE2s a contract whose runtime is SSTORE(0, 0x42) + STOP at a deterministic address. Tx2 (Bob) CALLs that address directly. BAL MUST include the target contract with nonce_changes and code_changes at block_access_index=1 (the deployment) and storage_changes for slot 0 (post=0x42) at block_access_index=2 (Tx2's CALL through the deployed runtime). Post-state: target contract has runtime code and slot[0] == 0x42. ✅ Completed
test_bal_cross_tx_factory_nonce_create_chain Verify clients propagate factory.nonce_changes across txs when later CREATE addresses derive from the factory's current nonce. The cross-tx dependency signal is solely nonce_changes — no storage or balance mutations exist anywhere. A scheduler that deprioritizes nonce_changes (or schedules CREATE-family txs by their resulting distinct addresses) would speculatively derive addr(factory, N+1) for every tx and produce only one successful deployment. Parametrized: failure_mode ∈ ["none", "collision", "oog"]collision pre-populates the mid-chain target (factory.nonce still bumps; chain slides forward); oog gives the mid-chain tx intrinsic+1 gas so CREATE never fires (factory.nonce does not bump; chain slides backward, reusing the slot). 8 txs from 8 distinct senders each call a shared factory that does CREATE with identical minimal initcode (deploys Op.STOP as runtime). none: factory has 8 sequential nonce_changes (post=N+1..N+8); each address has nonce_changes/code_changes at its block_access_index. collision: factory still has 8 sequential nonce_changes; the colliding target appears with BalAccountExpectation.empty() (accessed under EIP-684, no state change) and its pre-state code is preserved. oog: factory has only 7 nonce_changes (the OOG tx contributes none); subsequent post_nonce values are shifted -1; the OOG'd tx's would-be address slot is filled by the next tx; the final chain address is never touched (NONEXISTENT). Post-state: senders all nonce=1; factory nonce=N+(7 or 8) depending on mode. ✅ Completed
test_bal_cross_tx_balance_dependency Verify clients apply Tx1's balance change before executing Tx2 in the same block. A client that parallelizes Tx2 without applying Tx1's balance_changes would record the pre-block balance via SELFBALANCE, yielding a different state root. Parametrized over direct_call and selfdestruct funding paths so a client can't tie balance tracking to recipient-code execution. Tx1 (Alice) routes 1 wei into a branching contract (empty calldata → STOP). In direct_call, alice sends value directly; in selfdestruct, alice calls a pre-funded killer contract that SELFDESTRUCTs to the recipient (recipient bytecode never runs in Tx1). Tx2 (Bob) calls the contract with non-empty calldata, taking the SSTORE(0, SELFBALANCE) path. BAL MUST include the contract with balance_changes at block_access_index=1 (post=1) and storage_changes for slot 0 (post=1) at block_access_index=2. In selfdestruct, BAL also includes the killer with balance_changes (post=0) at index 1. Post-state: contract.balance == contract.storage[0] == 1 proves Tx2 observed Tx1's balance change. ✅ Completed
test_bal_7702_cross_tx_delegation_then_call Verify clients apply Tx1's EIP-7702 delegation before later txs CALL the now-delegated EOA. Three-tx chain forces clients to apply both the code-install and each intermediate storage increment for the final value to be correct. Tx1 (Relayer): sponsors an EIP-7702 auth that delegates Alice to a SSTORE(0, SLOAD(0) + 1) counter contract. Tx2 (Bob) and Tx3 (Charlie): both CALL Alice, which dispatches to the counter and increments her slot 0. BAL MUST include Alice with code_changes at block_access_index=1 (delegation designator), nonce_changes at index 1, and two storage_changes for slot 0 (post=1 at index 2, post=2 at index 3). Post-state: Alice has the delegation code and slot[0] == 2. ✅ Completed
test_bal_cross_tx_funding_chain Verify clients apply each tx's BAL balance_changes to the next sender's funds check. Five-tx chain across distinct senders, each intermediate starts empty and depends on the prior tx to be solvent. A parallelizing client validating any later tx against pre-block state would see zero balance on its sender and wrongly reject the block. Parametrized over success, oog_minus_1 (eunice's tx OOGs at exact gas minus one), and insufficient_funds (dan forwards one wei short so eunice's upfront balance check fails, block rejected with INSUFFICIENT_ACCOUNT_FUNDS). Tx1 alice→bob, Tx2 bob→charlie, Tx3 charlie→dan, Tx4 dan→eunice. Each forwards exactly the next sender's upfront cost. Tx5 eunice→target with runtime SSTORE(0, 0xC0FFEE). For success/oog_minus_1: BAL MUST include nonce/balance changes for each EOA at its tx's block_access_index, plus target's storage_changes at index 5 (success) or storage_reads=[0] (oog_minus_1). Post-state: all five EOAs end with balance=0; target has slot[0]==0xC0FFEE in success and empty storage in oog_minus_1. For insufficient_funds: block MUST be rejected with TransactionException.INSUFFICIENT_ACCOUNT_FUNDS. ✅ Completed
test_bal_withdrawal_predeploy_balance_observed_cross_tx Verify Tx2 observes Tx1's balance change on the EIP-7002 withdrawal predeploy via the BALANCE opcode. Exercises cross-tx visibility through a system address that is also touched by the prepare-block system call, so a client snapshotting the predeploy ahead of the BAL prefix would mask the overlay. Companion to test_bal_cross_tx_balance_dependency, which uses SELFBALANCE on a regular contract. File: tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_cross_index.py. Tx1 (sender_0) sends 1 wei (the fee at excess=0) to WITHDRAWAL_REQUEST_PREDEPLOY with a valid 56-byte withdrawal-request calldata; the predeploy retains the fee. Tx2 (sender_1) calls a reader contract whose runtime is SSTORE(0, BALANCE(WITHDRAWAL_REQUEST_PREDEPLOY)). BAL MUST include WITHDRAWAL_REQUEST_PREDEPLOY with balance_changes at block_access_index=1 (post=1) and the reader with storage_changes for slot 0 at block_access_index=2 (post=1). Post-state: reader.storage[0] == 1 proves Tx2's BALANCE opcode returned the post-Tx1 balance. ✅ Completed
test_bal_intra_tx_multiple_sstores_same_slot Ensure BAL coalesces consecutive SSTOREs to the same slot within one tx into a single storage change with the final post-value Contract executes SSTORE(0x01, 0xAA) + SSTORE(0x01, 0xBB) + SSTORE(0x01, 0xCC) in one tx. Parametrized by pre_value: slot_starts_empty (0x00), slot_starts_nonzero (0x11), intermediate_equals_pre (0xBB, where the second write transiently matches the pre-state). BAL MUST include contract with slot 0x01 having exactly one slot_changes entry: txIndex=1, post_value=0xCC. Intermediate values 0xAA and 0xBB MUST NOT appear as separate entries (enforced via absent_values). ✅ Completed
test_bal_intra_tx_sstores_same_slot_net_zero Ensure BAL filters net-zero result when multiple SSTOREs to the same slot occur within one tx Parametrized: nonzero_pre_returns_to_pre (pre=0xCC, writes 0xAA→0xBB→0xCC) and empty_pre_ephemeral_writes (pre=0x00, writes 0xAA→0xBB→0x00). Final value equals pre-state in both cases. BAL MUST include contract with slot 0x01 in storage_reads (slot was accessed) and MUST NOT include slot 0x01 in storage_changes (net-zero). ✅ Completed
test_bal_create_contract_init_revert Ensure BAL correctly handles CREATE when parent call reverts Caller calls factory, factory executes CREATE (succeeds), then factory REVERTs rolling back the CREATE BAL MUST include Alice with nonce_changes. Caller and factory with no changes (reverted). Created contract address appears in BAL but MUST NOT have nonce_changes or code_changes (CREATE was rolled back). Contract address MUST NOT exist in post-state. ✅ Completed
test_bal_create_oog_code_deposit Ensure BAL correctly handles CREATE OOG during code deposit Alice calls factory contract that executes CREATE with init code returning 10,000 bytes. Transaction has insufficient gas for code deposit. Factory nonce increments, CREATE returns 0 and stores in slot 1. BAL MUST include Alice with nonce_changes. Factory with nonce_changes (incremented by CREATE) and storage_changes (slot 1 = 0). Contract address with empty changes (read during collision check). MUST NOT include nonce or code changes for contract address (rolled back on OOG). Contract address MUST NOT exist in post-state. ✅ Completed
test_bal_create_early_failure Ensure BAL omits would-be address when CREATE/CREATE2 fails because of insufficient balance. Factory with balance below the endowment attempts CREATE/CREATE2; the call fails before the address is accessed. Alice: nonce_changes. Factory: storage_changes (CREATE returned 0), no nonce_changes. Would-be address MUST NOT appear in BAL. ✅ Completed
test_bal_invalid_missing_nonce Verify clients reject blocks with BAL missing required nonce changes Alice sends transaction to Bob; BAL modifier removes Alice's nonce change entry Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate that all sender accounts have nonce changes recorded. ✅ Completed
test_bal_invalid_nonce_value Verify clients reject blocks with incorrect nonce values in BAL Alice sends transaction to Bob; BAL modifier changes Alice's nonce to incorrect value Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate nonce values match actual state transitions. ✅ Completed
test_bal_invalid_storage_value Verify clients reject blocks with incorrect storage values in BAL Alice calls contract that writes to storage; BAL modifier changes storage value to incorrect value Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate storage change values match actual state transitions. ✅ Completed
test_bal_invalid_tx_order Verify clients reject blocks with incorrect transaction indices in BAL Alice sends transaction; BAL modifier swaps transaction indices incorrectly Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate transaction ordering matches actual block execution order. ✅ Completed
test_bal_invalid_account Verify clients reject blocks with incorrect account addresses in BAL Alice sends transaction; BAL modifier includes wrong account address Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate all account addresses in BAL were actually accessed. ✅ Completed
test_bal_invalid_duplicate_account Verify clients reject blocks with duplicate account entries in BAL Alice sends transaction; BAL modifier duplicates Alice's account entry Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST ensure each account appears at most once in BAL. ✅ Completed
test_bal_invalid_account_order Verify clients reject blocks with incorrect account ordering in BAL Alice sends transaction to Bob; BAL modifier reverses account order (BAL requires sorted order) Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate accounts are in canonical sorted order. ✅ Completed
test_bal_invalid_complex_corruption Verify clients reject blocks with multiple BAL corruptions Alice calls contract with storage writes; BAL has multiple issues: wrong account, missing nonce, wrong storage value Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST detect any corruption regardless of other issues. ✅ Completed
test_bal_invalid_missing_account Verify clients reject blocks whose BAL omits an account that was touched during block execution Parameterized test: balance_change — Alice sends a value transfer to Bob; BAL modifier removes Bob's entry (recipient had a balance change). access_only — Alice calls a contract that executes BALANCE against a target account without changing it; BAL modifier removes the target account's entry (accessed-but-unchanged). Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate all accessed accounts are present, including accessed-but-unchanged accounts with empty change lists. ✅ Completed
test_bal_invalid_balance_value Verify clients reject blocks with incorrect balance values in BAL Alice sends value to Bob; BAL modifier changes balance to incorrect value Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate balance change values match actual state transitions. ✅ Completed
test_bal_empty_block_no_coinbase Ensure BAL correctly handles empty blocks without including coinbase Block with 0 transactions, no withdrawals. System contracts may perform operations (EIP-2935 parent hash, EIP-4788 beacon root if active). BAL MUST NOT include the coinbase/fee recipient (receives no fees). BAL MAY include system contract addresses (EIP-2935 HISTORY_STORAGE_ADDRESS, EIP-4788 BEACON_ROOTS_ADDRESS) with storage_changes at block_access_index=0 (pre-execution system operations). ✅ Completed
test_bal_coinbase_zero_tip Ensure BAL includes coinbase even when priority fee is zero Block with 1 transaction: Alice sends 5 wei to Bob with priority fee = 0 (base fee burned post-EIP-1559) BAL MUST include Alice with balance_changes (gas cost) and nonce_changes. BAL MUST include Bob with balance_changes. BAL MUST include coinbase with empty changes. ✅ Completed
test_bal_withdrawal_empty_block Ensure BAL captures withdrawal balance changes in empty block Charlie starts with 1 gwei. Block with 0 transactions and 1 withdrawal of 10 gwei to Charlie BAL MUST include Charlie with balance_changes at block_access_index = 1. Charlie's balance_changes MUST show final balance of 11 gwei. All other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_withdrawal_and_transaction Ensure BAL captures both transaction and withdrawal balance changes Block with 1 transaction: Alice sends 5 wei to Bob. 1 withdrawal of 10 gwei to Charlie BAL MUST include Alice with nonce_changes and balance_changes at block_access_index = 1. BAL MUST include Bob with balance_changes at block_access_index = 1. BAL MUST include Charlie with balance_changes at block_access_index = 2 showing final balance after receiving 10 gwei. All other fields for Charlie MUST be empty. ✅ Completed
test_bal_withdrawal_to_nonexistent_account Ensure BAL captures withdrawal to non-existent account Block with 1 withdrawal of 10 gwei to non-existent account Charlie BAL MUST include Charlie with balance_changes at block_access_index = 1 showing final balance of 10 gwei. All other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_withdrawal_no_evm_execution Ensure BAL captures withdrawal without triggering EVM execution Contract Oracle with storage slot 0x01 = 0x42. Oracle code writes to slot 0x01 when called. Block with 1 withdrawal of 10 gwei to Oracle BAL MUST include Oracle with balance_changes at block_access_index = 1 showing final balance after receiving 10 gwei. Storage slot 0x01 MUST remain 0x42 and all other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_withdrawal_and_state_access_same_account Ensure BAL captures both state access and withdrawal to same address Contract Oracle with storage slot 0x01 = 0x42. Block with 1 transaction: Alice calls Oracle (reads from slot 0x01, writes to slot 0x02). 1 withdrawal of 10 gwei to Oracle BAL MUST include Oracle with storage_reads for slot 0x01 and storage_changes for slot 0x02 at block_access_index = 1. Oracle MUST also have balance_changes at block_access_index = 2 showing final balance after receiving 10 gwei. Both state access and withdrawal MUST be captured. ✅ Completed
test_bal_withdrawal_and_value_transfer_same_address Ensure BAL captures both transaction value transfer and withdrawal to same address Block with 1 transaction: Alice sends 5 gwei to Bob. 1 withdrawal of 10 gwei to Bob BAL MUST include Alice with nonce_changes and balance_changes at block_access_index = 1. BAL MUST include Bob with balance_changes at block_access_index = 1 showing balance after receiving 5 gwei. Bob MUST also have balance_changes at block_access_index = 2 showing balance after receiving 10 gwei withdrawal. Bob's final post-state balance MUST be 15 gwei (cumulative). ✅ Completed
test_bal_multiple_withdrawals_same_address Ensure BAL accumulates multiple withdrawals to same address Block with 3 withdrawals to Charlie: 5 gwei, 10 gwei, 15 gwei BAL MUST include Charlie with balance_changes at block_access_index = 1 showing final balance of 30 gwei. All other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_withdrawal_and_selfdestruct Ensure BAL captures withdrawal to self-destructed contract address Contract Oracle with 100 gwei balance. Block with 1 transaction: Oracle self-destructs sending balance to Bob. 1 withdrawal of 50 gwei to Oracle's address BAL MUST include Oracle with balance_changes showing 0 balance at block_access_index = 1 (after self-destruct). BAL MUST include Bob with balance_changes showing 100 gwei received from self-destruct at block_access_index = 1. Oracle MUST also have balance_changes at block_access_index = 2 showing 50 gwei after withdrawal. Both self-destruct and withdrawal MUST be captured. ✅ Completed
test_bal_withdrawal_and_new_contract Ensure BAL captures withdrawal to newly created contract Block with 1 transaction: Alice deploys contract Oracle with 5 gwei initial balance. 1 withdrawal of 10 gwei to Oracle BAL MUST include Oracle with code_changes and balance_changes showing 5 gwei at block_access_index = 1. Oracle MUST also have balance_changes at block_access_index = 2 showing balance after receiving 10 gwei withdrawal. Oracle's final post-state balance MUST be 15 gwei (cumulative). ✅ Completed
test_bal_zero_withdrawal Ensure BAL handles zero-amount withdrawal correctly Block with 0 transactions and 1 zero-amount withdrawal (0 gwei) to Charlie. Two variations: Charlie has existing balance (5 gwei) or Charlie is non-existent. BAL MUST include Charlie at block_access_index = 1 with empty changes. Balance remains unchanged. ✅ Completed
test_bal_withdrawal_to_precompiles Ensure BAL captures withdrawal to precompile addresses Block with 1 withdrawal of 10 gwei to precompile address (all precompiles) BAL MUST include precompile address with balance_changes at block_access_index = 1 showing final balance of 10 gwei. All other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_withdrawal_largest_amount Ensure BAL captures withdrawal with largest amount Block with 1 withdrawal of maximum uint64 value (2^64-1 gwei) to Charlie BAL MUST include Charlie with balance_changes at block_access_index = 1 showing final balance of (2^64-1) * 10^9 wei. All other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_withdrawal_to_coinbase Ensure BAL captures withdrawal to coinbase address Block with 1 transaction: Alice sends 5 wei to Bob. 1 withdrawal of 10 gwei to coinbase/fee recipient BAL MUST include coinbase with balance_changes at block_access_index = 1 showing balance after transaction fees. Coinbase MUST also have balance_changes at block_access_index = 2 showing balance after receiving 10 gwei withdrawal. Coinbase's final post-state balance MUST include both transaction fees and withdrawal. ✅ Completed
test_bal_withdrawal_to_coinbase_empty_block Ensure BAL captures withdrawal to coinbase even when there are no transactions (no fees) Block with 0 transactions and 1 withdrawal of 10 gwei to coinbase/fee recipient BAL MUST include coinbase with balance_changes at block_access_index = 1 showing final balance of 10 gwei. All other fields (storage_reads, storage_changes, nonce_changes, code_changes) MUST be empty. ✅ Completed
test_bal_nonexistent_value_transfer Ensure BAL captures non-existent account on value transfer Alice sends value (0 wei or 1 ETH) to non-existent account Bob (address never funded or accessed before) via direct transfer For zero value: BAL MUST include Alice with nonce_changes and Bob (non-existent) with empty changes. For positive value: BAL MUST include Bob with balance_changes showing received amount. ✅ Completed
test_bal_nonexistent_account_access_read_only Ensure BAL captures non-existent account accessed via read-only account-reading opcodes Alice calls Oracle contract which uses read-only account access opcodes (BALANCE, EXTCODESIZE, EXTCODECOPY, EXTCODEHASH, STATICCALL, DELEGATECALL) on non-existent account Bob. BAL MUST include Alice with nonce_changes, Oracle with empty changes, and Bob with empty changes (account accessed but no state modifications). ✅ Completed
test_bal_nonexistent_account_access_value_transfer Ensure BAL captures non-existent account accessed via CALL/CALLCODE with value transfers Alice calls Oracle contract which uses CALL or CALLCODE on non-existent account Bob. Tests both zero and positive value transfers. BAL MUST include Alice with nonce_changes. For CALL with positive value: Oracle with balance_changes (loses value), Bob with balance_changes (receives value). For CALLCODE with value or zero value transfers: Oracle and Bob with empty changes (CALLCODE self-transfer = net zero). ✅ Completed
test_bal_storage_write_read_same_frame Ensure BAL captures write precedence over read in same call frame (writes shadow reads) Alice calls Oracle which writes (SSTORE) value 0x42 to slot 0x01, then reads (SLOAD) from slot 0x01 in the same call frame BAL MUST include Oracle with slot 0x01 in storage_changes showing final value 0x42. Slot 0x01 MUST NOT appear in storage_reads (write shadows the subsequent read in same frame). ✅ Completed
test_bal_storage_write_read_cross_frame Ensure BAL captures write precedence over read across call frames (writes shadow reads cross-frame) Alice calls Oracle. First call reads slot 0x01 (sees initial value), writes 0x42 to slot 0x01, then calls itself (via CALL, DELEGATECALL, or CALLCODE). Second call reads slot 0x01 (sees 0x42) and exits. BAL MUST include Oracle with slot 0x01 in storage_changes showing final value 0x42. Slot 0x01 MUST NOT appear in storage_reads (write shadows both the read before it in same frame and the read in the recursive call). ✅ Completed
test_bal_create_transaction_empty_code Ensure BAL does not record spurious code changes for CREATE transaction deploying empty code Alice sends CREATE transaction with empty initcode (deploys code b""). Contract address gets nonce = 1 and code = b"". BAL MUST include Alice with nonce_changes and created contract with nonce_changes but MUST NOT include code_changes for contract (setting b"" -> b"" is net-zero). ✅ Completed
test_bal_cross_block_ripemd160_state_leak Ensure internal EVM state for precompile handling does not leak between blocks Block 1: Alice calls RIPEMD-160 (0x03) with zero value (RIPEMD-160 must be pre-funded). Block 2: Bob's transaction triggers an exception (stack underflow). BAL for Block 1 MUST include RIPEMD-160. BAL for Block 2 MUST NOT include RIPEMD-160 (never accessed in Block 2). Internal state from Parity Touch Bug (EIP-161) handling must be reset between blocks. ✅ Completed
test_bal_all_transaction_types Ensure BAL correctly captures state changes from all transaction types in a single block Single block with 5 transactions: Type 0 (Legacy), Type 1 (EIP-2930 Access List), Type 2 (EIP-1559), Type 3 (EIP-4844 Blob), Type 4 (EIP-7702 Set Code). Each tx writes to contract storage. Note: Access list addresses are pre-warmed but NOT recorded in BAL (no state access). BAL MUST include: (1) All 5 senders with nonce_changes. (2) Contracts 0-3 with storage_changes. (3) Alice (7702 target) with nonce_changes, code_changes (delegation), storage_changes. (4) Oracle (delegation source) with empty changes. ✅ Completed
test_bal_create_collision Ensure BAL handles CREATE/CREATE2 address collision correctly, with or without a subsequent tx that modifies the colliding address. Parametrized: @pytest.mark.with_all_create_opcodes, modification ∈ {"collision_only", "then_nonce_change", "then_storage_change"}. Factory (nonce=1, slot[0]=0xDEAD) executes CREATE/CREATE2 targeting a pre-populated address X. For collision_only, X is code=STOP, nonce=1. For then_nonce_change, X is a contract that runs its own inner CREATE when called. For then_storage_change, X is a contract that SSTOREs when called. If modification != "collision_only", a second tx (from Bob) calls X. BAL MUST include: (1) Factory with nonce_changes (1→2, bumped even on failed CREATE/CREATE2), storage_changes for slot 0 (0xDEAD→0). (2) X for the collision touch at index 1. For collision_only, X's BAL entry is empty(). For then_nonce_change, X has nonce_changes at index 2 (post=2) and the inner-created child has nonce_changes/code_changes at index 2; X MUST NOT have spurious code_changes/storage_changes/storage_reads/balance_changes. For then_storage_change, X has storage_changes for slot 0x01 (post=0xCAFE) at index 2; MUST NOT have spurious entries on other axes. ✅ Completed
test_bal_create2_deploy_then_collision Ensure BAL correctly preserves a colliding address's deployment entries when the same address is later touched again via a collision check, and that init code does NOT execute on the collision. Tx1: factory CREATE2 deploys X; X's init code does SSTORE(0, SLOAD(0)+1) (increment) then deploys STOP. Tx2: same factory retries the identical CREATE2 — collision against X. BAL MUST include: (1) Factory with nonce_changes at indices 1 and 2 (1→2→3) and storage_changes at slot 0 with entries at indices 1 (post=X.address) and 2 (post=0 from the failed CREATE2 return). (2) X with nonce_changes=[(1, 1)], code_changes=[(1, STOP)], and storage_changes slot 0 [(1, 1)] from the deployment; no entries at index 2 and storage_reads MUST be empty — a client that runs init then reverts on collision would leak slot 0 as a demoted read. Post-state: X slot 0 == 1 proves init executed exactly once (tx2 collided, didn't re-run init). ✅ Completed
test_bal_create_selfdestruct_to_self_with_call Ensure BAL handles init code that calls external contract then selfdestructs to itself Factory executes CREATE2 with endowment=100. Init code (embedded in factory via CODECOPY): (1) CALL(Oracle, 0) - Oracle writes to its storage slot 0x01. (2) SSTORE(0x01, 0x42) - write to own storage. (3) SELFDESTRUCT(SELF) - selfdestruct to own address. Contract created and destroyed in same tx. BAL MUST include: (1) Factory with nonce_changes, balance_changes (loses 100). (2) Oracle with storage_changes for slot 0x01 (external call succeeded). (3) Created address with storage_reads for slot 0x01 (aborted write becomes read) - MUST NOT have nonce_changes, code_changes, storage_changes, or balance_changes (ephemeral contract, balance burned via SELFDESTRUCT to self). ✅ Completed
test_bal_selfdestruct_to_7702_delegation Ensure BAL correctly handles SELFDESTRUCT to a 7702 delegated account (no code execution on recipient) Tx1: Alice authorizes delegation to Oracle (sets code to 0xef0100\|\|Oracle). Tx2: Victim contract (balance=100) executes SELFDESTRUCT(Alice). Two separate transactions in same block. Note: Alice starts with initial balance which accumulates with selfdestruct. BAL MUST include: (1) Alice at block_access_index=1 with code_changes (delegation), nonce_changes. (2) Alice at block_access_index=2 with balance_changes (receives selfdestruct). (3) Victim at block_access_index=2 with balance_changes (100→0). Oracle MUST NOT appear in tx2 - per EVM spec, SELFDESTRUCT transfers balance without executing recipient code, so delegation target is never accessed. ✅ Completed
test_bal_call_revert_insufficient_funds Ensure BAL handles value-transferring call failure due to insufficient balance (not OOG), with and without 7702 delegation Caller contract (balance=100, storage slot 0x02=0xDEAD) executes: SLOAD(0x01), call_opcode(target, value=1000), SSTORE(0x02, result). The call fails because 1000 > 100. Parametrized: (1) call_opcode over CALL and CALLCODE via with_all_call_opcodes(selector=...), (2) delegated (target is plain EOA vs. 7702-delegated EOA pointing to delegation_target=STOP), (3) target_is_warm (cold/warm via EIP-2930 access list), (4) delegation_is_warm (only when delegated). BAL MUST include: (1) Caller with storage_reads for slot 0x01, storage_changes for slot 0x02 (value=0, call returned failure). (2) Target with empty changes — accessed before the balance check fails. (3) When delegated: delegation_target MUST NOT appear in the BAL — the balance check fails before generic_call runs, so the delegation target's account is never read. Access-list warming does NOT add to BAL on its own, so the BAL is identical across warm/cold variants. ✅ Completed
test_bal_lexicographic_address_ordering Ensure BAL enforces strict lexicographic byte-wise ordering Pre-fund three addresses with specific byte patterns: addr_low = 0x0000...0001, addr_mid = 0x0000...0100, addr_high = 0x0100...0000. Contract touches them in reverse order: BALANCE(addr_high), BALANCE(addr_low), BALANCE(addr_mid). Additionally, include two endian-trap addresses that are byte-reversals of each other: addr_endian_low = 0x0100000000000000000000000000000000000002, addr_endian_high = 0x0200000000000000000000000000000000000001. Note: reverse(addr_endian_low) = addr_endian_high. Correct lexicographic order: addr_endian_low < addr_endian_high (0x01 < 0x02 at byte 0). If implementation incorrectly reverses bytes before comparing, it would get addr_endian_low > addr_endian_high (wrong). BAL account list MUST be sorted lexicographically by address bytes: addr_low < addr_mid < addr_high < addr_endian_low < addr_endian_high, regardless of access order. The endian-trap addresses specifically catch byte-reversal bugs where addresses are compared with wrong byte order. Complements test_bal_invalid_account_order which tests rejection; this tests correct generation. ✅ Completed
test_bal_gas_limit_boundary Ensure the BAL max-items cap is enforced on the final BAL — including pre-tx system work, user txs, and post-tx system work. Parametrized on two orthogonal axes: with_tx ∈ {False, True} × with_cl_withdrawal ∈ {False, True} × boundary_offset ∈ {at, below}. The with_cl_withdrawal axis exercises the EIP-4895 withdrawals path (processed between txs and process_general_purpose_requests); combined with with_tx it catches clients that validate the cap before process_withdrawals runs. Baseline: 15 system items. with_tx: alice → bob value=1 adds 3 items (alice + bob + coinbase warmed via EIP-3651). with_cl_withdrawal: one EIP-4895 withdrawal to charlie adds 1 item at block_access_index = N+1. Gas limit set to total_items * BLOCK_ACCESS_LIST_ITEM + boundary_offset. At boundary: block MUST be accepted; BAL includes alice's nonce_change, bob's balance_change (when with_tx), charlie's balance_change at the post-tx index (when with_cl_withdrawal). Below boundary: block MUST be rejected with BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED. ✅ Completed
test_bal_transient_storage_not_tracked Ensure BAL excludes EIP-1153 transient storage operations Contract executes: TSTORE(0x01, 0x42) (transient write), TLOAD(0x01) (transient read), SSTORE(0x02, result) (persistent write using transient value). BAL MUST include slot 0x02 in storage_changes (persistent storage was modified). BAL MUST NOT include slot 0x01 in storage_reads or storage_changes (transient storage is not persisted, not needed for stateless execution). This verifies TSTORE/TLOAD don't pollute BAL. ✅ Completed
test_bal_withdrawal_to_7702_delegation Ensure BAL correctly handles withdrawal to a 7702 delegated account (no code execution on recipient) Tx1: Alice authorizes delegation to Oracle (sets code to 0xef0100\|\|Oracle). Withdrawal: 10 gwei sent to Alice. Single block with tx + withdrawal. BAL MUST include: (1) Alice at block_access_index=1 with code_changes (delegation), nonce_changes. (2) Alice at block_access_index=2 with balance_changes (receives withdrawal). Oracle MUST NOT appear - withdrawals credit balance without executing recipient code, so delegation target is never accessed. This complements test_bal_selfdestruct_to_7702_delegation (selfdestruct) and test_bal_withdrawal_no_evm_execution (withdrawal to contract). ✅ Completed
test_init_collision_create_tx Ensure BAL tracks CREATE collisions correctly (pre-Amsterdam test with BAL) CREATE transaction targeting address with existing storage aborts BAL MUST show empty expectations for collision address (no changes occur due to abort) ✅ Completed
test_call_to_pre_authorized_oog Ensure BAL handles OOG during EIP-7702 delegation access (pre-Amsterdam test with BAL) Call to delegated account that OOGs before accessing delegation contract BAL MUST include auth_signer (code read for delegation check) but MUST NOT include delegation contract (OOG before access) ✅ Completed
test_selfdestruct_created_in_same_tx_with_revert Ensure BAL tracks selfdestruct with revert correctly (pre-Amsterdam test with BAL) Contract created and selfdestructed in same tx with nested revert BAL MUST track storage reads and balance changes for selfdestruct even with reverts ✅ Completed
test_value_transfer_gas_calculation Ensure BAL correctly tracks OOG scenarios for CALL/CALLCODE/DELEGATECALL/STATICCALL (pre-Amsterdam test with BAL) Nested calls with precise gas limits to test OOG behavior. For CALL with OOG: target account is read. For CALLCODE/DELEGATECALL/STATICCALL with OOG: target account NOT read (OOG before state access) For CALL: target in BAL even with OOG. For CALLCODE/DELEGATECALL/STATICCALL: target NOT in BAL when OOG (state access deferred until after gas check) ✅ Completed
test_bal_call_with_value_in_static_context Ensure BAL does NOT include target when CALL with value fails in static context static_caller uses STATICCALL to call caller. caller attempts CALL(target, value=1) which must fail due to static context. Target is an empty account. BAL MUST NOT include target because static context check (is_static && value > 0) must happen BEFORE any account access or BAL tracking. BAL MUST include static_caller with storage_changes (STATICCALL succeeded), caller with empty changes. ✅ Completed
test_staticcall_reentrant_call_to_precompile Ensure BAL captures STATICCALL reentry with CALL to precompile Contract STATICCALLs itself. On reentry (CALLVALUE=0), attempts CALL to precompile with parametrized value. File: tests/byzantium/eip214_staticcall/test_staticcall.py. call_value=0: target with storage_changes (slot 0=1), precompile with empty changes. call_value>0: target with storage_reads (slot 0), precompile NOT in BAL (reverted before accessed). ✅ Completed
test_staticcall_call_to_precompile Ensure BAL captures STATICCALL → CALL to precompile chain Contract A STATICCALLs contract B. B attempts CALL to precompile. File: tests/byzantium/eip214_staticcall/test_staticcall.py. call_value=0: contract_a with markers, contract_b empty (STATICCALLed), precompile empty. call_value>0: contract_a with storage_reads for slot 1, precompile NOT in BAL. ✅ Completed
test_staticcall_nested_call_to_precompile Ensure BAL captures nested CALL → STATICCALL → CALL to precompile Contract B CALLs A. A STATICCALLs C. C attempts CALL to precompile. File: tests/byzantium/eip214_staticcall/test_staticcall.py. call_value=0: all contracts with markers/empty, precompile empty. call_value>0: contract_a with storage_reads for slot 1, precompile NOT in BAL. ✅ Completed
test_staticcall_call_to_precompile_from_contract_init Ensure BAL captures STATICCALL to precompile during CREATE init Contract A CREATEs contract. Init code STATICCALLs B which CALLs precompile. File: tests/byzantium/eip214_staticcall/test_staticcall.py. call_value=0: contract_a with markers/nonce, created_contract with markers/nonce, contract_b empty, precompile empty. call_value>0: created_contract with storage_reads for slot 1, precompile NOT in BAL. ✅ Completed
test_bal_4788_simple Ensure BAL captures beacon root storage writes during pre-execution system call Block with 2 normal user transactions: Alice sends 10 wei to Charlie, Bob sends 10 wei to Charlie. At block start (pre-execution), SYSTEM_ADDRESS calls BEACON_ROOTS_ADDRESS to store parent beacon root BAL MUST include at block_access_index=0: BEACON_ROOTS_ADDRESS with two storage_changes (timestamp slot and beacon root slot); SYSTEM_ADDRESS MUST NOT be included in BAL. At block_access_index=1: Alice with nonce_changes, Charlie with balance_changes (10 wei). At block_access_index=2: Bob with nonce_changes, Charlie with balance_changes (20 wei total). ✅ Completed
test_bal_4788_empty_block Ensure BAL captures beacon root storage writes in empty block Block with no transactions. At block start (pre-execution), SYSTEM_ADDRESS calls BEACON_ROOTS_ADDRESS to store parent beacon root BAL MUST include at block_access_index=0: BEACON_ROOTS_ADDRESS with two storage_changes (timestamp slot and beacon root slot); SYSTEM_ADDRESS MUST NOT be included in BAL. No transaction-related BAL entries. ✅ Completed
test_bal_4788_query Ensure BAL captures storage reads when querying beacon root (valid and invalid queries) with optional value transfer Parameterized test: Block 1 stores beacon root at timestamp 12. Block 2 queries with three timestamp scenarios (valid=12, invalid non-zero=42, invalid zero=0) and value (0 or 100 wei). Valid query (timestamp=12): reads both timestamp and root slots, writes returned value. If value > 0, beacon root contract receives balance. Invalid query with non-zero timestamp (timestamp=42): reads only timestamp slot before reverting, query contract has implicit SLOAD recorded (SSTORE reverts), no value transferred. Invalid query with zero timestamp (timestamp=0): reverts immediately without any storage access, query contract has implicit SLOAD recorded, no value transferred. Block 1 BAL: System call writes. Block 2 BAL MUST include at block_access_index=0: System call writes for block 2. Valid case (timestamp=12) at block_access_index=1: BEACON_ROOTS_ADDRESS with storage_reads [timestamp_slot, root_slot] and balance_changes if value > 0, query contract with storage_changes. Invalid non-zero case (timestamp=42) at block_access_index=1: BEACON_ROOTS_ADDRESS with storage_reads [timestamp_slot only] and NO balance_changes (reverted), query contract with storage_reads [0] and NO storage_changes. Invalid zero case (timestamp=0) at block_access_index=1: BEACON_ROOTS_ADDRESS with NO storage_reads (reverts before access) and NO balance_changes, query contract with storage_reads [0] and NO storage_changes. ✅ Completed
test_bal_4788_invalid_calldata_size Ensure BAL correctly handles EIP-4788 queries with invalid calldata size Parameterized test: Query contract calls BEACON_ROOTS_ADDRESS with variable-size calldata (0, 31, or 33 bytes) and value (0 or 100 wei). EIP-4788 requires exactly 32 bytes of calldata; any other size reverts before any storage access. BAL MUST include at block_access_index=0: BEACON_ROOTS_ADDRESS with storage_changes from system call. At block_access_index=1: BEACON_ROOTS_ADDRESS with NO storage_reads (reverts before access) and NO balance_changes (value not transferred), query contract with storage_reads [0] (implicit from no-op SSTORE) and NO storage_changes. If value > 0, query contract retains balance. Alice with nonce_changes. ✅ Completed
test_bal_4788_selfdestruct_to_beacon_root Ensure BAL captures SELFDESTRUCT to beacon root address alongside system call storage writes Single block: Pre-execution system call writes beacon root to storage. Transaction: Alice calls contract (pre-funded with 100 wei) that selfdestructs with BEACON_ROOTS_ADDRESS as beneficiary. BAL MUST include at block_access_index=0: BEACON_ROOTS_ADDRESS with storage_changes (timestamp and root slots from system call). At block_access_index=1: Alice with nonce_changes, contract with balance_changes (100→0), BEACON_ROOTS_ADDRESS with balance_changes (receives 100 wei). ✅ Completed
test_selfdestruct_send_to_sender Ensure BAL tracks SELFDESTRUCT sending all funds back to the tx sender (no burn). Multi-fork: valid_from TangerineWhistle, BAL expectations applied from Amsterdam via is_eip_enabled(7928). File: tests/tangerine_whistle/eip150_operation_gas_costs/test_eip150_selfdestruct.py. Parametrized over originator_balance: [0, 100]. Pre-deployed contract victim with code=SELFDESTRUCT(CALLER) and the given balance. Alice (tx.sender) sends tx directly to victim; no intermediate caller. Pre-Cancun: victim destroyed. >=Cancun (EIP-6780, non-same-tx): victim preserved with balance 0. When EIP-7928 is enabled, BAL MUST include Alice with nonce_changes coalesced with balance_changes (Alice is both sender and beneficiary). Victim has balance_changes 100→0 when funded, otherwise empty changes — and MUST NOT have code_changes or nonce_changes. ✅ Completed
test_bal_7002_clean_sweep Ensure BAL correctly tracks "clean sweep" where all withdrawal requests are dequeued in same block (requests ≤ MAX). Parameterized: (1) pubkey first 32 bytes zero / non-zero, (2) amount zero / non-zero Alice sends transaction to WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS with 1 withdrawal request. Validator pubkey has either first 32 bytes zero or non-zero. Amount is either zero or non-zero. Since 1 ≤ MAX_WITHDRAWAL_REQUESTS_PER_BLOCK, post-execution system call dequeues all requests ("clean sweep"), resetting head and tail to 0. BAL MUST include Alice with nonce_changes at block_access_index=1. WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS MUST have: balance_changes at block_access_index=1 (receives fee), storage_reads for excess, head, and slot 5 (first 32 bytes of pubkey) if zero. At block_access_index=1 (tx enqueue): storage_changes for count (0→1), tail (0→1), slot 4 (source address), slot 5 (first 32 bytes, ONLY if non-zero), slot 6. At block_access_index=2 (post-exec dequeue): storage_changes for count (1→0), tail (1→0). Clean sweep invariant: when all requests dequeued, both head and tail reset to 0. ✅ Completed
test_bal_7002_partial_sweep Ensure BAL correctly tracks queue overflow when requests exceed MAX, demonstrating partial sweep in block 1 and cleanup in block 2 Block 1: 20 different EOAs each send withdrawal request to WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS. Since 20 > MAX_WITHDRAWAL_REQUESTS_PER_BLOCK, only first MAX requests dequeued ("partial sweep"), leaving 4 in queue. Block 2: Empty block (no transactions), remaining 4 requests dequeued ("clean sweep"), queue becomes empty. Block 1 BAL MUST include all 20 senders with nonce_changes at respective block_access_index (1-20). WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS at each tx: storage_changes for count (increments to 20), tail (increments to 20). At block_access_index=21 (post-exec partial dequeue): storage_changes for count (20→0), head (0→MAX). Partial sweep: head advances by MAX, tail stays 20, queue has 4 remaining (tail - head = 4). Block 2 BAL MUST include WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS at block_access_index=1 (post-exec clean sweep): storage_changes for head (MAX→0), tail (20→0). Clean sweep: both head and tail reset to 0, queue empty. ✅ Completed
test_bal_7002_no_withdrawal_requests Ensure BAL captures EIP-7002 system contract dequeue operation even when block has no withdrawal requests Block with 1 transaction: Alice sends 10 wei to Bob. No withdrawal requests submitted. BAL MUST include Alice with nonce_changes at block_access_index=1. BAL MUST include Bob with balance_changes at block_access_index=1. BAL MUST include EIP-7002 system contract (WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS) with storage_reads for slots: excess (slot 0), count (slot 1), head (slot 2), tail (slot 3). System contract MUST NOT have storage_changes (no writes occur when queue is empty). This test demonstrates that the post-execution dequeue operation always runs and reads queue state, even when no requests are present. ✅ Completed
test_bal_7002_request_from_contract Ensure BAL captures withdrawal request from contract with correct source address Alice calls RelayContract which internally calls EIP-7002 system contract with withdrawal request. Withdrawal request should have source_address = RelayContract (not Alice). BAL MUST include Alice with nonce_changes at block_access_index=1. BAL MUST include RelayContract with balance_changes (fee paid to system contract) at block_access_index=1. BAL MUST include system contract with balance_changes, storage_reads, and storage_changes (queue modified). Source address in withdrawal request MUST be RelayContract. Clean sweep: count and tail reset to 0 at block_access_index=2. ✅ Completed
test_bal_7002_request_invalid Ensure BAL correctly handles invalid withdrawal request scenarios Parameterized test with 8 invalid scenarios: (1) insufficient_fee (fee=0), (2) calldata_too_short (55 bytes), (3) calldata_too_long (57 bytes), (4) oog (insufficient gas), (5-7) invalid_call_type (DELEGATECALL/STATICCALL/CALLCODE), (8) contract_reverts. Tests both EOA and contract-based withdrawal requests. BAL MUST include sender with nonce_changes at block_access_index=1. BAL MUST include system contract with storage_reads for slots: excess (slot 0), count (slot 1), head (slot 2), tail (slot 3). System contract MUST NOT have storage_changes (transaction failed, no queue modification). ✅ Completed
test_bal_invalid_extraneous_entries Verify clients reject blocks with any type of extraneous BAL entries Alice sends 100 wei to Oracle contract (which reads storage slot 0). Charlie is uninvolved in this transaction. A valid BAL is created containing nonce change for Alice, balance change and storage read for Oracle. The BAL is corrupted by adding various extraneous entries: (1) extra_nonce, (2) extra_balance, (3) extra_code, (4) extra_storage_write_touched (slot 0 - already read), (5) extra_storage_write_untouched (slot 1 - not accessed), (6) extra_storage_write_uninvolved_account (Charlie - uninvolved account), (7) extra_account_access (Charlie), (8) extra_storage_read (slot 999). Each tested at block_access_index 1 (same tx), 2 (system tx), 3 (out of bounds). Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST detect any extraneous entries in BAL. ✅ Completed
test_bal_invalid_duplicate_entries Verify clients reject blocks where BAL violates uniqueness constraints Oracle writes storage, reads storage, and CREATEs a contract. BAL is corrupted with duplicate entries: (1) duplicate_nonce_change, (2) duplicate_balance_change, (3) duplicate_code_change, (4) duplicate_storage_slot, (5) duplicate_storage_read, (6) duplicate_slot_change, (7) storage_key_in_both_changes_and_reads. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Each block_access_index must appear at most once per change list, each storage key at most once in storage_changes and storage_reads, and no key in both. ✅ Completed
test_bal_invalid_missing_withdrawal_account Verify clients reject blocks where BAL is missing an account modified only by a withdrawal Alice sends 5 wei to Bob (1 transaction). Charlie receives 10 gwei withdrawal. BAL modifier removes Charlie's entry entirely. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST detect that Charlie's balance was modified by the withdrawal but has no corresponding BAL entry. ✅ Completed
test_bal_invalid_missing_withdrawal_account_empty_block Verify clients reject blocks where BAL is missing a withdrawal-modified account in an empty block Charlie receives 10 gwei withdrawal in block with no transactions. BAL modifier removes Charlie's entry entirely. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST detect withdrawal-modified accounts even when no transactions are present. ✅ Completed
test_bal_invalid_hash_mismatch Verify clients reject blocks where the BAL hash in the header does not match the actual BAL content Alice sends value to Bob. BAL content is valid but header hash is overridden to a wrong value via rlp_modifier. Unlike other invalid BAL tests (which corrupt BAL content with matching hash), this keeps the BAL valid but injects a wrong header hash. Block MUST be rejected with INVALID_BAL_HASH or INVALID_BLOCK_HASH exception. Clients MUST re-derive the BAL from block execution and compare its hash to the header, not just verify the BAL content is self-consistent. ✅ Completed
test_bal_invalid_field_entries Verify clients reject blocks with missing or incorrect field-level BAL entries Oracle writes storage slot 1, reads storage slot 2, and CREATEs a small contract. A valid BAL is created, then corrupted by parameterized modifier: (1) missing_storage_change: Oracle's storage writes removed, (2) missing_storage_read: Oracle's storage reads removed, (3) missing_code_change: created contract's code change removed, (4) wrong_code_value: created contract's deployed bytecode changed to wrong value. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate all field-level BAL entries: storage writes, storage reads, and code changes. ✅ Completed
test_bal_invalid_withdrawal_balance_value Verify clients reject blocks where BAL has an incorrect balance value for a withdrawal-modified account Charlie receives 10 gwei withdrawal in an empty block. BAL modifier changes Charlie's post-balance from the correct 10_000_000_000 wei to 999. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate withdrawal balance values match actual withdrawal amounts (including gwei-to-wei conversion). ✅ Completed
test_bal_invalid_missing_coinbase Verify clients reject blocks where BAL is missing the coinbase/fee recipient Alice sends 100 wei to Bob with gas_price > base_fee so coinbase (charlie) receives a non-zero tip. BAL modifier removes charlie's entry entirely. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST include fee recipients that received tips in the BAL. ✅ Completed
test_bal_invalid_coinbase_balance_value Verify clients reject blocks where BAL has an incorrect balance for the coinbase/fee recipient Same setup as test_bal_invalid_missing_coinbase. BAL modifier changes charlie's post-balance from the actual tip to 999. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Clients MUST validate coinbase balance values match actual fee accounting (priority fee x gas used). ✅ Completed
test_bal_invalid_extraneous_coinbase Verify clients reject blocks with a spurious coinbase entry when coinbase received no fees Parameterized: (1) empty_block: no txs, no withdrawals — only system contracts in valid BAL, (2) withdrawal_only: no txs, one withdrawal to a different address — withdrawals don't pay fees so coinbase is still untouched. BAL modifier appends spurious coinbase entry with empty changes. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST exception. Coinbase MUST NOT appear in BAL when it receives no transaction tips, even if the block has other state-modifying activity (withdrawals). ✅ Completed
test_bal_invalid_surplus_system_address_from_system_call Verify clients reject a BAL containing SYSTEM_ADDRESS solely due to a system operation caller Empty block with an EIP-4788 pre-execution system call to BEACON_ROOTS_ADDRESS. Helper beacon_root_system_call_expectations builds the valid baseline BAL: BEACON_ROOTS_ADDRESS has timestamp/root storage changes at block_access_index=0, while SYSTEM_ADDRESS is marked absent (None). The fixture BAL is then corrupted by appending an empty SYSTEM_ADDRESS entry. Block MUST be rejected with INVALID_BLOCK_ACCESS_LIST. The synthetic system caller address MUST NOT be accepted unless it experienced an actual state access. ✅ Completed
test_bal_2935_simple Ensure BAL captures EIP-2935 history storage writes during pre-execution system call alongside normal transactions Block with 2 normal user transactions: Alice sends 10 wei to Charlie, Bob sends 10 wei to Charlie. At block start (pre-execution), SYSTEM_ADDRESS calls HISTORY_STORAGE_ADDRESS to store parent block hash. BAL MUST include HISTORY_STORAGE_ADDRESS with storage_changes (ring buffer slot 0, empty slot_changes since parent hash is framework-computed); SYSTEM_ADDRESS MUST NOT be included in BAL. At block_access_index=1: Alice with nonce_changes, Charlie with balance_changes (10 wei). At block_access_index=2: Bob with nonce_changes, Charlie with balance_changes (20 wei total). ✅ Completed
test_bal_2935_empty_block Ensure BAL captures EIP-2935 history storage writes in empty block Block with no transactions. At block start (pre-execution), SYSTEM_ADDRESS calls HISTORY_STORAGE_ADDRESS to store parent block hash. BAL MUST include HISTORY_STORAGE_ADDRESS with storage_changes (ring buffer slot 0, empty slot_changes); SYSTEM_ADDRESS MUST NOT be included in BAL. No transaction-related BAL entries. ✅ Completed
test_bal_2935_query Ensure BAL captures storage reads when querying EIP-2935 historical block hashes (valid and invalid queries) with optional value transfer Parameterized test: Block 1 (empty, stores genesis hash via system call). Block 2: Oracle contract queries HISTORY_STORAGE_ADDRESS with block number. Two block number scenarios (valid=0 genesis hash, invalid=1042 out of range) and value (0 or 100 wei). Valid query (block_number=0): reads genesis hash slot, oracle writes returned value. If value > 0, history storage contract receives balance. Invalid query (block_number=1042, out of range): reverts before storage access, oracle has implicit SLOAD recorded, value stays in oracle (not transferred to history storage). Block 2 BAL MUST include: Valid case at block_access_index=1: HISTORY_STORAGE_ADDRESS with storage_reads [slot 0] and balance_changes if value > 0, oracle with storage_changes (empty slot_changes). Invalid case at block_access_index=1: HISTORY_STORAGE_ADDRESS with NO storage_reads (reverts before access) and NO balance_changes, oracle with storage_reads [0], NO storage_changes, and balance_changes if value > 0 (value stays in oracle). Alice with nonce_changes at block_access_index=1. ✅ Completed
test_bal_2935_selfdestruct_to_history_storage Ensure BAL captures SELFDESTRUCT to EIP-2935 history storage address Single block: Transaction where Alice calls contract (pre-funded with 100 wei) that selfdestructs with HISTORY_STORAGE_ADDRESS as beneficiary. BAL MUST include at block_access_index=1: Alice with nonce_changes, contract with balance_changes (100→0), HISTORY_STORAGE_ADDRESS with balance_changes (receives 100 wei). ✅ Completed
test_bal_2935_invalid_calldata_size Ensure BAL correctly handles EIP-2935 queries with invalid calldata size (reverts before any storage access) Parameterized test: Block 1 stores genesis hash via system call. Block 2: Oracle contract calls HISTORY_STORAGE_ADDRESS with invalid calldata sizes (0, 31, 33 bytes). EIP-2935 requires exactly 32 bytes calldata; any other size causes immediate revert before storage access. Optional value transfer (0 or 100 wei). Block 2 BAL MUST include: HISTORY_STORAGE_ADDRESS with NO storage_reads (calldata size check fails before any SLOAD) and NO balance_changes (call reverts). Oracle with storage_reads [0] (implicit SLOAD from no-op SSTORE), NO storage_changes, and balance_changes if value > 0 (value stays in oracle on revert). Alice with nonce_changes. ✅ Completed
test_bal_create2_selfdestruct_then_recreate_same_block Ensure BAL handles (tx1) CREATE2+SSTORE+SELFDESTRUCT then (tx2) CREATE2 "resurrection" of the same address in the same block. Parametrized over pre_balance: [0, 100]. Two identical txs invoke the same factory with the same initcode (same hash → same CREATE2 address A). The factory branches on its own storage[1]: on the first tx, slot 1 is 0 so the factory CREATE2's then CALLs A (runtime SSTOREs to a target slot then SELFDESTRUCTs to beneficiary) and records the CALL's return code in slot 1; on the second tx, slot 1 is non-zero so only CREATE2 runs and A persists with the runtime code (its runtime is never executed). When pre_balance > 0, A is pre-funded so Tx1's SELFDESTRUCT transfers a real balance. At block_access_index=1 (destructed A): MUST NOT include nonce_changes or code_changes for A (EIP-7928 SELFDESTRUCT-in-tx semantics); the SSTORE is demoted to storage_reads for the target slot (write demoted because A is destroyed same-tx). balance_changes for A appears only when pre-funded. Beneficiary appears with balance_changes if pre-funded, otherwise empty() (SELFDESTRUCT touches the beneficiary even with 0 value). At block_access_index=2 (resurrection): A has nonce_changes (post=1) and code_changes (post=runtime). Post-state: A has empty storage={} (the tx1 SSTORE was wiped; tx2 never executed the runtime). Factory's storage[1] = 1 confirms the Tx1 CALL went through. ✅ Completed
test_bal_call_with_value_in_static_context CALL with nonzero value in static context: target NOT in BAL Parametrized: target_is_warm (cold/warm via access list), target_has_code (EOA/contract). Static check must fire before account access. target MUST NOT appear in BAL. Balances unchanged. ✅ Completed
test_bal_create_in_static_context CREATE/CREATE2 in static context: created address NOT in BAL Parametrized: @pytest.mark.with_all_create_opcodes, value (0/1). Static check must fire before balance check, address computation, or nonce increment. Created address MUST NOT appear in BAL. Factory nonce unchanged. ✅ Completed
test_bal_selfdestruct_in_static_context SELFDESTRUCT in static context: beneficiary NOT in BAL Parametrized: beneficiary_is_warm (cold/warm via access list), caller_balance (0/100). Static check must fire before beneficiary access or balance transfer. beneficiary MUST NOT appear in BAL. Balances unchanged. ✅ Completed
test_bal_call_opcode_succeeds_in_static_context All call opcodes (no value) succeed in static context Parametrized: @pytest.mark.with_all_call_opcodes. Caller invokes call_opcode(target) inside STATICCALL. target MUST appear in BAL. Ensures clients don't over-restrict beyond EIP-214. ✅ Completed
test_bal_callcode_with_value_in_static_context CALLCODE with nonzero value succeeds in static context EIP-214 explicitly excludes CALLCODE from write-protection. Caller invokes CALLCODE(value=1, target) inside STATICCALL. target MUST appear in BAL. Ensures clients don't apply CALL-with-value restriction to CALLCODE. ✅ Completed
test_bal_create_and_oog CREATE/CREATE2 OOG boundary test at three gas levels Parametrized: @pytest.mark.with_all_create_opcodes, OutOfGasBoundary (OOG_BEFORE_TARGET_ACCESS, OOG_AFTER_TARGET_ACCESS, SUCCESS). BEFORE and AFTER differ by 1 gas, proving the static cost boundary. OOG_BEFORE: created address MUST NOT appear in BAL. OOG_AFTER: created address IS in BAL as empty() (accessed, state reverted). SUCCESS: created address in BAL with nonce_changes/code_changes. ✅ Completed
test_bal_fork_transition_happy_path Verify a BAL is produced at the Amsterdam activation block and absent before it. File: tests/amsterdam/eip7928_block_level_access_lists/test_fork_transition.py. Uses @pytest.mark.valid_at_transition_to("Amsterdam") to run across the BPO2 -> Amsterdam boundary. Two blocks: pre-fork (timestamp=14_999) with a simple Alice→Bob transfer, then activation block (timestamp=15_000) with the same kind of transfer. Pre-fork block header MUST NOT carry block_access_list_hash. Activation block MUST include block_access_list_hash correctly derived from the BAL body, and the BAL body MUST record Alice's nonce_changes and Bob's balance_changes at block_access_index=1. ✅ Completed
test_invalid_pre_fork_block_with_bal_hash_field Verify clients reject a pre-Amsterdam block whose header carries block_access_list_hash. File: tests/amsterdam/eip7928_block_level_access_lists/test_fork_transition.py. Single block at timestamp=14_999 with a regular transfer, mutated via rlp_modifier=Header(block_access_list_hash=Hash(0)) to inject the field into the pre-fork header schema. Block MUST be rejected with BlockException.INVALID_BLOCK_HASH: pre-fork clients compute the block hash without the injected field, mismatching the expected hash. ✅ Completed
test_invalid_post_fork_block_without_bal_hash_field Verify clients reject an Amsterdam activation block whose header is missing block_access_list_hash. File: tests/amsterdam/eip7928_block_level_access_lists/test_fork_transition.py. Single block at timestamp=15_000 with a regular transfer, mutated via rlp_modifier=Header(block_access_list_hash=Header.REMOVE_FIELD) so the field is dropped from the header. Block MUST be rejected with BlockException.INVALID_BAL_HASH: clients re-derive the BAL hash from execution and find no header hash to match. The engine fixture omits the blockAccessList param from newPayloadV5, which MUST return -32602: Invalid params. ✅ Completed
test_fork_transition_bal_size_constraint Verify the BAL size constraint (bal_items <= gas_limit // BLOCK_ACCESS_LIST_ITEM) applies only on/after Amsterdam. File: tests/amsterdam/eip7928_block_level_access_lists/test_fork_transition.py. Parametrized over exceeds_limit_at_fork: at_fork_within_budget (gas_limit == empty_block_bal_item_count() * BLOCK_ACCESS_LIST_ITEM) and at_fork_over_budget (gas_limit one wei below that). Two empty blocks: pre-fork (timestamp=14_999) and activation block (timestamp=15_000). The same low gas_limit is used for both via genesis_environment=Environment(gas_limit=...). Pre-fork block MUST be accepted under both budgets (constraint not yet enforced). Activation block MUST be accepted at the exact budget and MUST be rejected with BlockException.BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED one item over the budget. ✅ Completed
test_bal_dirty_account_selfdestruct Ensure BAL does not record dirty state on a same-tx ephemeral contract whose SELFDESTRUCT takes effect. A factory deploys an ephemeral whose initcode dirties balance, nonce, code, and storage; runtime SELFDESTRUCT routes through an intermediate oracle. success: ephemeral's BAL entry contains only storage_reads for the demoted slots. revert: BAL records all four dirty fields (destruction rolled back). ✅ Completed