Skip to content

Commit edee4d8

Browse files
raxhvlfselmo
authored andcommitted
✨ feat(tests): EIP-7928 tests for EIP-2930:
🧹 chore(tests): Move to new test file ✨ feat(tests): EIP-7928test_bal_2930_slot_listed_and_unlisted_reads ✨ feat(tests): EIP-7928 test_bal_2930_slot_listed_and_unlisted_writes ✨ feat(tests): EIP-7928 test_bal_2930_slot_listed_but_untouched
1 parent 4215632 commit edee4d8

File tree

2 files changed

+202
-3
lines changed

2 files changed

+202
-3
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
"""Tests for EIP-7928 for EIP-2930 transactions."""
2+
3+
import pytest
4+
5+
from ethereum_test_tools import (
6+
AccessList,
7+
Account,
8+
Alloc,
9+
Block,
10+
BlockchainTestFiller,
11+
Hash,
12+
Transaction,
13+
)
14+
from ethereum_test_tools.vm.opcode import Opcodes as Op
15+
from ethereum_test_types.block_access_list import (
16+
BalAccountExpectation,
17+
BalNonceChange,
18+
BalStorageChange,
19+
BalStorageSlot,
20+
BlockAccessListExpectation,
21+
)
22+
23+
from .spec import ref_spec_7928
24+
25+
REFERENCE_SPEC_GIT_PATH = ref_spec_7928.git_path
26+
REFERENCE_SPEC_VERSION = ref_spec_7928.version
27+
28+
pytestmark = pytest.mark.valid_from("Amsterdam")
29+
30+
31+
def test_bal_2930_slot_listed_but_untouched(
32+
pre: Alloc,
33+
blockchain_test: BlockchainTestFiller,
34+
fork,
35+
):
36+
"""Ensure BAL excludes untouched access list storage slots."""
37+
alice = pre.fund_eoa()
38+
pure_calculator = pre.deploy_contract(
39+
# Pure add operation
40+
Op.ADD(35, 7)
41+
)
42+
43+
access_list = AccessList(
44+
address=pure_calculator,
45+
storage_keys=[Hash(0x1)],
46+
)
47+
48+
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
49+
gas_limit = (
50+
intrinsic_gas_calculator(
51+
calldata=b"",
52+
contract_creation=False,
53+
access_list=[access_list],
54+
)
55+
+ 1000
56+
) # intrinsic + buffer
57+
58+
tx = Transaction(
59+
ty=1, sender=alice, to=pure_calculator, gas_limit=gas_limit, access_list=[access_list]
60+
)
61+
62+
block = Block(
63+
txs=[tx],
64+
expected_block_access_list=BlockAccessListExpectation(
65+
account_expectations={
66+
alice: BalAccountExpectation(
67+
nonce_changes=[BalNonceChange(tx_index=1, post_nonce=1)],
68+
),
69+
# The address excluded from BAL since state is not accessed
70+
pure_calculator: None,
71+
}
72+
),
73+
)
74+
75+
blockchain_test(
76+
pre=pre,
77+
blocks=[block],
78+
post={
79+
alice: Account(nonce=1),
80+
},
81+
)
82+
83+
84+
def test_bal_2930_slot_listed_and_unlisted_writes(
85+
pre: Alloc,
86+
blockchain_test: BlockchainTestFiller,
87+
fork,
88+
):
89+
"""Ensure BAL includes storage writes regardless of access list presence."""
90+
alice = pre.fund_eoa()
91+
storage_writer = pre.deploy_contract(code=Op.SSTORE(0x01, 0x42) + Op.SSTORE(0x02, 0x43))
92+
93+
# Access list only includes slot 0x01, but contract writes to both 0x01 and 0x02
94+
access_list = AccessList(
95+
address=storage_writer,
96+
storage_keys=[Hash(0x01)],
97+
)
98+
99+
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
100+
gas_limit = (
101+
intrinsic_gas_calculator(
102+
calldata=b"",
103+
contract_creation=False,
104+
access_list=[access_list],
105+
)
106+
+ 50000
107+
) # intrinsic + buffer for storage writes
108+
109+
tx = Transaction(
110+
ty=1, sender=alice, to=storage_writer, gas_limit=gas_limit, access_list=[access_list]
111+
)
112+
113+
block = Block(
114+
txs=[tx],
115+
expected_block_access_list=BlockAccessListExpectation(
116+
account_expectations={
117+
alice: BalAccountExpectation(
118+
nonce_changes=[BalNonceChange(tx_index=1, post_nonce=1)],
119+
),
120+
storage_writer: BalAccountExpectation(
121+
storage_changes=[
122+
BalStorageSlot(
123+
slot=0x01,
124+
slot_changes=[BalStorageChange(tx_index=1, post_value=0x42)],
125+
),
126+
BalStorageSlot(
127+
slot=0x02,
128+
slot_changes=[BalStorageChange(tx_index=1, post_value=0x43)],
129+
),
130+
],
131+
),
132+
}
133+
),
134+
)
135+
136+
blockchain_test(
137+
pre=pre,
138+
blocks=[block],
139+
post={
140+
alice: Account(nonce=1),
141+
storage_writer: Account(storage={0x01: 0x42, 0x02: 0x43}),
142+
},
143+
)
144+
145+
146+
def test_bal_2930_slot_listed_and_unlisted_reads(
147+
pre: Alloc,
148+
blockchain_test: BlockchainTestFiller,
149+
fork,
150+
):
151+
"""Ensure BAL includes storage reads regardless of access list presence."""
152+
alice = pre.fund_eoa()
153+
storage_reader = pre.deploy_contract(
154+
code=Op.SLOAD(0x01) + Op.SLOAD(0x02),
155+
storage={0x01: 0x42, 0x02: 0x43}, # Pre-populate storage with values
156+
)
157+
158+
# Access list only includes slot 0x01, but contract reads from both 0x01 and 0x02
159+
access_list = AccessList(
160+
address=storage_reader,
161+
storage_keys=[Hash(0x01)],
162+
)
163+
164+
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
165+
gas_limit = (
166+
intrinsic_gas_calculator(
167+
calldata=b"",
168+
contract_creation=False,
169+
access_list=[access_list],
170+
)
171+
+ 50000
172+
) # intrinsic + buffer for storage reads
173+
174+
tx = Transaction(
175+
ty=1, sender=alice, to=storage_reader, gas_limit=gas_limit, access_list=[access_list]
176+
)
177+
178+
block = Block(
179+
txs=[tx],
180+
expected_block_access_list=BlockAccessListExpectation(
181+
account_expectations={
182+
alice: BalAccountExpectation(
183+
nonce_changes=[BalNonceChange(tx_index=1, post_nonce=1)],
184+
),
185+
storage_reader: BalAccountExpectation(
186+
storage_reads=[0x01, 0x02],
187+
),
188+
}
189+
),
190+
)
191+
192+
blockchain_test(
193+
pre=pre,
194+
blocks=[block],
195+
post={
196+
alice: Account(nonce=1),
197+
storage_reader: Account(storage={0x01: 0x42, 0x02: 0x43}),
198+
},
199+
)

tests/amsterdam/eip7928_block_level_access_lists/test_cases.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
| `test_bal_storage_reads` | Ensure BAL captures storage reads | Alice calls contract that reads from storage slot `0x01` | BAL MUST include storage access for the read operation | ✅ Completed |
99
| `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 |
1010
| `test_bal_self_destruct` | Ensure BAL captures storage access and balance changes caused by `SELFDESTRUCT` | Parameterized test: Alice interacts with a contract (either existing or created same-tx) that reads from storage slot 0x01, writes to storage slot 0x02, then executes `SELFDESTRUCT` with Bob as recipient. Contract may be pre-funded with 10 wei | BAL MUST include Alice's nonce change (increment) and Bob's balance change (100 or 110 depending on pre-funding). For the self-destructing contract: storage_reads=[0x01], empty storage_changes=[], and if pre-funded, balance_changes with post_balance=0; if not pre-funded, no balance change recorded. MUST NOT have code_changes or nonce_changes entries | ✅ Completed |
11-
| `test_bal_2930_slot_listed_but_untouched` | Ensure 2930 access list alone doesn't appear in BAL | Include `(KV, S=0x01)` in tx's EIP-2930 access list; tx executes code that does **no** `SLOAD`/`SSTORE` to `S` (e.g., pure arithmetic/log). | BAL **MUST NOT** contain any entry for `(KV, S)` — neither reads nor writes — because the slot wasn't touched. | 🟡 Planned |
1211
| `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 |
1312
| `test_bal_call_with_value_transfer` | Ensure BAL captures balance changes from `CALL` opcode with value transfer | Alice calls `Oracle` contract (200 wei balance) which uses `CALL` opcode to transfer 100 wei to Bob (0 wei balance). | BAL MUST include Alice (nonce changes), Oracle (balance change to 100 wei), and Bob (balance change to 100 wei). | ✅ Completed |
1413
| `test_bal_callcode_with_value_transfer` | Ensure BAL captures balance changes from `CALLCODE` opcode with value transfer | Alice calls `Oracle` contract (200 wei balance) which uses `CALLCODE` opcode to execute `TargetContract`'s code with 100 wei value transfer to Bob (0 wei balance). | BAL MUST include Alice (nonce changes), `Oracle` (balance change to 100 wei), Bob (balance change to 100 wei), and `TargetContract` (empty changes). | ✅ Completed |
1514
| `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 |
1615
| `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 |
1716
| `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 |
18-
| `test_bal_2930_slot_listed_but_untouched` | Ensure 2930 access list alone doesn’t appear in BAL | Include `(KV, S=0x01)` in tx’s EIP-2930 access list; tx executes code that does **no** `SLOAD`/`SSTORE` to `S` (e.g., pure arithmetic/log). | BAL **MUST NOT** contain any entry for `(KV, S)` — neither reads nor writes — because the slot wasn’t touched. | 🟡 Planned |
19-
| `test_bal_2930_slot_listed_and_modified` | Ensure BAL records writes only because the slot is touched | Same access list as above, but tx executes `SSTORE` to `S`. | BAL **MUST** include `storage_changes` for `(KV, S)` (and no separate read record for that slot if implementation deduplicates). Presence in the access list is irrelevant; inclusion is due to the actual write. | 🟡 Planned |
17+
| `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 |
18+
| `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 |
19+
| `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 |
2020
| `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`. | 🟡 Planned |
2121
| `test_bal_self_transfer` | BAL handles self-transfers correctly | Alice sends `1 ETH` to **Alice** | BAL MUST include **one** entry for Alice with `balance_changes` reflecting **gas only** (value cancels out) and a nonce change; Coinbase balance updated for fees; no separate recipient row. | 🟡 Planned |
2222
| `test_bal_system_contracts_2935_4788` | BAL includes pre-exec system writes for parent hash & beacon root | Build a block with `N` normal txs; 2935 & 4788 active | BAL MUST include `HISTORY_STORAGE_ADDRESS` (EIP-2935) and `BEACON_ROOTS_ADDRESS` (EIP-4788) with `storage_changes` to ring-buffer slots; each write uses `tx_index = N` (system op). | 🟡 Planned |

0 commit comments

Comments
 (0)