Skip to content

Commit d5735c5

Browse files
qu0bfselmo
authored andcommitted
test(eip7928): add cross-block precompile state leak test
1 parent 4a3a7e0 commit d5735c5

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,3 +2206,80 @@ def test_bal_cross_tx_storage_revert_to_zero(
22062206
contract: Account(storage={0: 0x0}),
22072207
},
22082208
)
2209+
2210+
2211+
# RIPEMD-160 precompile address (used in Parity Touch Bug test)
2212+
RIPEMD_160 = Address(0x03)
2213+
2214+
2215+
def test_bal_cross_block_precompile_state_leak(
2216+
pre: Alloc,
2217+
blockchain_test: BlockchainTestFiller,
2218+
) -> None:
2219+
"""
2220+
Ensure internal EVM state for precompile handling does not leak between blocks.
2221+
2222+
The EVM may track internal state related to the Parity Touch Bug (EIP-161)
2223+
when calling RIPEMD-160 (0x03) with zero value. If this state is not properly
2224+
reset between blocks, it can cause incorrect BAL entries in subsequent blocks.
2225+
2226+
Prerequisites for triggering the bug:
2227+
1. RIPEMD-160 (0x03) must already exist in state before the call.
2228+
2. Block 1 must call RIPEMD-160 with zero value and complete successfully.
2229+
3. Block 2 must have a TX that triggers an exception (not REVERT).
2230+
2231+
Expected behavior:
2232+
- Block 1: RIPEMD-160 in BAL (legitimate access)
2233+
- Block 2: RIPEMD-160 NOT in BAL (never touched in this block)
2234+
2235+
Bug behavior:
2236+
- Block 2 incorrectly has RIPEMD-160 in its BAL due to leaked internal state.
2237+
"""
2238+
alice = pre.fund_eoa()
2239+
bob = pre.fund_eoa()
2240+
2241+
# Pre-fund RIPEMD-160 so it exists before the call.
2242+
# This is required to trigger the internal state tracking.
2243+
pre[RIPEMD_160] = Account(balance=1)
2244+
2245+
# Contract that calls RIPEMD-160 with zero value
2246+
ripemd_caller = pre.deploy_contract(
2247+
code=Op.CALL(50_000, RIPEMD_160, 0, 0, 0, 0, 0) + Op.STOP
2248+
)
2249+
2250+
# Contract that triggers an exception (stack underflow from ADD on empty stack)
2251+
exception_contract = pre.deploy_contract(code=Op.ADD)
2252+
2253+
# Block 1: Call RIPEMD-160 successfully
2254+
block1 = Block(
2255+
txs=[
2256+
Transaction(
2257+
sender=alice,
2258+
to=ripemd_caller,
2259+
gas_limit=100_000,
2260+
)
2261+
],
2262+
)
2263+
2264+
# Block 2: Exception triggers internal exception handling.
2265+
# If internal state leaked from Block 1, RIPEMD-160 would incorrectly
2266+
# appear in Block 2's BAL.
2267+
block2 = Block(
2268+
txs=[
2269+
Transaction(
2270+
sender=bob,
2271+
to=exception_contract,
2272+
gas_limit=100_000,
2273+
)
2274+
],
2275+
)
2276+
2277+
blockchain_test(
2278+
pre=pre,
2279+
blocks=[block1, block2],
2280+
post={
2281+
alice: Account(nonce=1),
2282+
bob: Account(nonce=1),
2283+
RIPEMD_160: Account(balance=1),
2284+
},
2285+
)

tests/amsterdam/eip7928_block_level_access_lists/test_cases.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,4 @@
9494
| `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 |
9595
| `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 |
9696
| `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 read for `is_account_alive` check. 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 |
97+
| `test_bal_cross_block_precompile_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 |

0 commit comments

Comments
 (0)