Skip to content

Commit 484ebb6

Browse files
fselmoraxhvlnerolation
authored
feat(tests): Support for EIP-7928 - Block-Level Access Lists (#2067)
* 🚧 wip(EIP-7928): Block-level Access Lists * ✨ feat(EIP-7928): Spec params * 🧹 chore(EIP-7928): Rename package * ✨ feat(EIP-7928): Test cases * ✨ feat(EIP-7928): Add BAL header * 🧹 chore(EIP-7928): bal_hash header * 🧹 chore: Populate bal_hash env * ✨ feat(EIP-7928): Add BAL to block body * ✨ feat(EIP-7928): Add pokebal package * ✨ feat: update env * 🚧 wip: Checklist and basic tests * 🧹 chore: scope * Add more sophisticated test cases (#2029) Co-authored-by: raxhvl <[email protected]> * WIP: Attempt to get EEST + EELS bals PRs talking to each other * refactor(bal): Use full bal in t8n; verify and build fixtures - Use the full bal object in the t8n. We can use this to model_validate() into our pydantic model. - Also, pass the bal_hash via t8n so that once we do build the BAL, validate the explicitly defined values, rlp encode it, then hash it, we can compare the full BAL against the hash and make sure that even though we only validated the part that was important for our test, the full BAL is also always valid. Bonus: - Added a new type for ``StorageKey`` because these were not being rlp encoded properly without the left padding. This was tricky to find and I think this can be a common issue. New type here seemed appropriate. * chore(lint): Fix lint issues, assign method to Frontier to be overridden * fix(tests,lint): Set up code changes test case; fix remaining lint issues * refactor(forks): move BAL tests to Amsterdam - chore(cleanup): Remove reference to told BlockAccessLists fork - refactor(fork): ``Amsterdam`` above old EOF fork. * chore: Fix CI lint issues not present locally - Update some docstrings to remove AI excessive verbosity and add CodeChanges case to example. * refactor(bal): Apply comments from first pass at PR - Use ``Number`` instead of ``int`` where appropriate - Use ``default_factory=list`` without ``Optional`` and ``None`` where appropriate * refactor(bal): Split BAL into two classes - Use a root model class for the t8n BAL model. This lets us stick closer to the EIP definition where the BAL itself is a list. - The class doesn't need to be `RLPSerializable`, just have simple instructions to serialize its elements (`rlp()`). - Create a `BlockAccessListExpectation` class to represent the expected BAL for a given block. This class can describe different expectations for the test cases, such as defining mutations to be used for invalid tests. * refactor(tests): Rename checklist.md -> test_cases.md for BAL test case tracking * feat(tests,tools): [WIP] initial invalid BAL tests * chore(spec-resolver): Update commit hash to point to for spec resolver * fix(lint,resolver): Use latest commit in resolver; fix lint * Address comments from PR #2067 * chore(docs): Add changelog entries for BAL updates * refactor(types): Refactor BAL checks for explicit exclusion of acct changes - From comments on PR #2067, we should allow for an explicit exclusion case for an entire set of account changes. If a test case warrants a sanity check that some account might have been impacted but shouldn't be accounted for, we should be able to specify that explicitly. * fix(bal): Fix explicit empty checks for account changes; add unit tests * feat(bal): Extend BAL support within framework - Add BAL to engine execution payload as defined in: https://github.com/ethereum/consensus-specs/pull/4526/files#diff-4b950f0c895b4d521c9e8103d638e73a4c7746c6aea51250994425a1efd6f4c8R55 - Add BAL support for state tests to be able to create blockchain tests * fix(warnings): Silence warning for unused reference in .md file * fix(bal): Move state test expected bal to Block * feat(release): Set up BAL work for a feature release * fix: BAL as object in fixture block so RLP is correct * chore(pytest): Add Amsterdam to ruleset for simulator plugin --------- Co-authored-by: raxhvl <[email protected]> Co-authored-by: Toni Wahrstätter <[email protected]> Co-authored-by: raxhvl <[email protected]>
1 parent 6331511 commit 484ebb6

File tree

26 files changed

+2377
-242
lines changed

26 files changed

+2377
-242
lines changed

.github/configs/eels_resolutions.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,10 @@
4848
},
4949
"BPO4": {
5050
"same_as": "Osaka"
51+
},
52+
"Amsterdam": {
53+
"git_url": "https://github.com/fselmo/execution-specs.git",
54+
"branch": "feat/amsterdam-fork-and-block-access-lists",
55+
"commit": "a5c7b29a658320c2432de78883d350e9f4444d14"
5156
}
5257
}

.github/configs/feature.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ benchmark_develop:
1515
evm-type: develop
1616
fill-params: --fork=Osaka --gas-benchmark-values 1,10,30,45,60,100,150 -m "benchmark and not state_test" ./tests/benchmark
1717
feature_only: true
18+
19+
bal:
20+
evm-type: develop
21+
fill-params: --fork=Amsterdam ./tests/amsterdam/eip7928_block_level_access_lists
22+
feature_only: true

docs/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ Users can select any of the artifacts depending on their testing needs for their
141141
- 🔀 Move Prague to stable and Osaka to develop ([#1573](https://github.com/ethereum/execution-spec-tests/pull/1573)).
142142
- ✨ Add a `pytest.mark.with_all_typed_transactions` marker that creates default typed transactions for each `tx_type` supported by the current `fork` ([#1890](https://github.com/ethereum/execution-spec-tests/pull/1890)).
143143
- ✨ Add basic support for ``Amsterdam`` fork in order to begin testing Glamsterdam ([#2069](https://github.com/ethereum/execution-spec-tests/pull/2069)).
144+
-[EIP-7928](https://eips.ethereum.org/EIPS/eip-7928): Add initial framework support for `Block Level Access Lists (BAL)` testing for Amsterdam ([#2067](https://github.com/ethereum/execution-spec-tests/pull/2067)).
144145

145146
### 🧪 Test Cases
146147

@@ -154,12 +155,13 @@ Users can select any of the artifacts depending on their testing needs for their
154155
-[EIP-7951](https://eips.ethereum.org/EIPS/eip-7951): add test cases for `P256VERIFY` precompile to support secp256r1 curve [#1670](https://github.com/ethereum/execution-spec-tests/pull/1670).
155156
- ✨ Introduce blockchain tests for benchmark to cover the scenario of pure ether transfers [#1742](https://github.com/ethereum/execution-spec-tests/pull/1742).
156157
-[EIP-7934](https://eips.ethereum.org/EIPS/eip-7934): Add test cases for the block RLP max limit of 10MiB ([#1730](https://github.com/ethereum/execution-spec-tests/pull/1730)).
157-
-[EIP-7939](https://eips.ethereum.org/EIPS/eip-7939) Add count leading zeros (CLZ) opcode tests for Osaka ([#1733](https://github.com/ethereum/execution-spec-tests/pull/1733)).
158+
-[EIP-7939](https://eips.ethereum.org/EIPS/eip-7939): Add count leading zeros (CLZ) opcode tests for Osaka ([#1733](https://github.com/ethereum/execution-spec-tests/pull/1733)).
158159
-[EIP-7934](https://eips.ethereum.org/EIPS/eip-7934): Add additional test cases for block RLP max limit with all typed transactions and for a log-creating transactions ([#1890](https://github.com/ethereum/execution-spec-tests/pull/1890)).
159160
-[EIP-7825](https://eips.ethereum.org/EIPS/eip-7825): Pre-Osaka tests have been updated to either (1) dynamically adapt to the transaction gas limit cap, or (2) reduce overall gas consumption to fit the new limit ([#1924](https://github.com/ethereum/EIPs/pull/1924), [#1928](https://github.com/ethereum/EIPs/pull/1928), [#1980](https://github.com/ethereum/EIPs/pull/1980)).
160161
-[EIP-7918](https://eips.ethereum.org/EIPS/eip-7918): Blob base fee bounded by execution cost test cases (initial), includes some adjustments to [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) tests ([#1685](https://github.com/ethereum/execution-spec-tests/pull/1685)).
161162
- 🔀 Adds the max blob transaction limit to the tests including updates to [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) for Osaka ([#1884](https://github.com/ethereum/execution-spec-tests/pull/1884)).
162163
- 🐞 Fix issues when filling block rlp size limit tests with ``--generate-pre-alloc-groups`` ([#1989](https://github.com/ethereum/execution-spec-tests/pull/1989)).
164+
-[EIP-7928](https://eips.ethereum.org/EIPS/eip-7928): Add test cases for `Block Level Access Lists (BAL)` to Amsterdam ([#2067](https://github.com/ethereum/execution-spec-tests/pull/2067)).
163165

164166
## [v4.5.0](https://github.com/ethereum/execution-spec-tests/releases/tag/v4.5.0) - 2025-05-14
165167

docs/running_tests/test_formats/blockchain_test_sync.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The test works by:
1515
3. Having the sync client synchronize from the client under test.
1616
4. Verifying that both clients reach the same final state.
1717

18-
A single JSON fixture file is composed of a JSON object where each key-value pair is a different [`SyncFixture`](#syncfixture) test object, with the key string representing the test name.
18+
A single JSON fixture file is composed of a JSON object where each key-value pair is a different [`HiveFixture`](#hivefixture) test object, with the key string representing the test name.
1919

2020
The JSON file path plus the test name are used as the unique test identifier, as well as a `{client under test}::sync_{sync client}` identifier.
2121

src/ethereum_clis/types.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
TransactionException,
1313
UndefinedException,
1414
)
15-
from ethereum_test_types import Alloc, Environment, Transaction, TransactionReceipt
15+
from ethereum_test_types import (
16+
Alloc,
17+
BlockAccessList,
18+
Environment,
19+
Transaction,
20+
TransactionReceipt,
21+
)
1622

1723

1824
class TransactionExceptionWithMessage(ExceptionWithMessage[TransactionException]):
@@ -57,6 +63,8 @@ class Result(CamelModel):
5763
blob_gas_used: HexNumber | None = None
5864
requests_hash: Hash | None = None
5965
requests: List[Bytes] | None = None
66+
block_access_list: BlockAccessList | None = None
67+
block_access_list_hash: Hash | None = None
6068
block_exception: Annotated[
6169
BlockExceptionWithMessage | UndefinedException | None, ExceptionMapperValidator
6270
] = None

src/ethereum_test_base_types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
HexNumber,
1515
Number,
1616
NumberBoundTypeVar,
17+
StorageKey,
1718
Wei,
1819
ZeroPaddedHexNumber,
1920
)
@@ -72,6 +73,7 @@
7273
"RLPSerializable",
7374
"SignableRLPSerializable",
7475
"Storage",
76+
"StorageKey",
7577
"StorageRootType",
7678
"TestAddress",
7779
"TestAddress2",

src/ethereum_test_base_types/base_types.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,20 @@ class Hash(FixedSizeBytes[32]): # type: ignore
383383
pass
384384

385385

386+
class StorageKey(FixedSizeBytes[32]): # type: ignore
387+
"""
388+
Storage key type that automatically applies left padding for values shorter
389+
than 32 bytes.
390+
"""
391+
392+
def __new__(cls, value, **kwargs):
393+
"""Create a new StorageKey with automatic left padding."""
394+
# Always apply left_padding for storage keys unless explicitly set to False
395+
if "left_padding" not in kwargs:
396+
kwargs["left_padding"] = True
397+
return super().__new__(cls, value, **kwargs)
398+
399+
386400
class Bloom(FixedSizeBytes[256]): # type: ignore
387401
"""Class that helps represent blooms in tests."""
388402

src/ethereum_test_fixtures/blockchain.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from ethereum_test_exceptions import EngineAPIError, ExceptionInstanceOrList
3939
from ethereum_test_forks import Fork, Paris
4040
from ethereum_test_types import (
41+
BlockAccessList,
4142
Environment,
4243
Requests,
4344
Transaction,
@@ -165,6 +166,9 @@ class FixtureHeader(CamelModel):
165166
None
166167
)
167168
requests_hash: Annotated[Hash, HeaderForkRequirement("requests")] | None = Field(None)
169+
block_access_list_hash: Annotated[Hash, HeaderForkRequirement("bal_hash")] | None = Field(
170+
None, alias="blockAccessListHash"
171+
)
168172

169173
fork: Fork | None = Field(None, exclude=True)
170174

@@ -231,6 +235,9 @@ def genesis(cls, fork: Fork, env: Environment, state_root: Hash) -> "FixtureHead
231235
extras = {
232236
"state_root": state_root,
233237
"requests_hash": Requests() if fork.header_requests_required(0, 0) else None,
238+
"block_access_list_hash": (
239+
BlockAccessList().rlp_hash if fork.header_bal_hash_required(0, 0) else None
240+
),
234241
"fork": fork,
235242
}
236243
return FixtureHeader(**environment_values, **extras)
@@ -262,21 +269,27 @@ class FixtureExecutionPayload(CamelModel):
262269
transactions: List[Bytes]
263270
withdrawals: List[Withdrawal] | None = None
264271

272+
block_access_list: Bytes | None = Field(
273+
None, description="RLP-serialized EIP-7928 Block Access List"
274+
)
275+
265276
@classmethod
266277
def from_fixture_header(
267278
cls,
268279
header: FixtureHeader,
269280
transactions: List[Transaction],
270281
withdrawals: List[Withdrawal] | None,
282+
block_access_list: Bytes | None = None,
271283
) -> "FixtureExecutionPayload":
272284
"""
273285
Return FixtureExecutionPayload from a FixtureHeader, a list
274-
of transactions and a list of withdrawals.
286+
of transactions, a list of withdrawals, and an optional block access list.
275287
"""
276288
return cls(
277289
**header.model_dump(exclude={"rlp"}, exclude_none=True),
278290
transactions=[tx.rlp() for tx in transactions],
279291
withdrawals=withdrawals,
292+
block_access_list=block_access_list,
280293
)
281294

282295

@@ -331,6 +344,7 @@ def from_fixture_header(
331344
transactions: List[Transaction],
332345
withdrawals: List[Withdrawal] | None,
333346
requests: List[Bytes] | None,
347+
block_access_list: Bytes | None = None,
334348
**kwargs,
335349
) -> "FixtureEngineNewPayload":
336350
"""Create `FixtureEngineNewPayload` from a `FixtureHeader`."""
@@ -344,6 +358,7 @@ def from_fixture_header(
344358
header=header,
345359
transactions=transactions,
346360
withdrawals=withdrawals,
361+
block_access_list=block_access_list,
347362
)
348363

349364
params: List[Any] = [execution_payload]
@@ -428,6 +443,9 @@ class FixtureBlockBase(CamelModel):
428443
ommers: List[FixtureHeader] = Field(default_factory=list, alias="uncleHeaders")
429444
withdrawals: List[FixtureWithdrawal] | None = None
430445
execution_witness: WitnessChunk | None = None
446+
block_access_list: BlockAccessList | None = Field(
447+
None, description="EIP-7928 Block Access List"
448+
)
431449

432450
@computed_field(alias="blocknumber") # type: ignore[misc]
433451
@cached_property
@@ -446,6 +464,9 @@ def with_rlp(self, txs: List[Transaction]) -> "FixtureBlock":
446464
if self.withdrawals is not None:
447465
block.append([w.to_serializable_list() for w in self.withdrawals])
448466

467+
if self.block_access_list is not None:
468+
block.append(self.block_access_list.to_list())
469+
449470
return FixtureBlock(
450471
**self.model_dump(),
451472
rlp=eth_rlp.encode(block),

src/ethereum_test_forks/base_fork.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ def header_requests_required(cls, block_number: int = 0, timestamp: int = 0) ->
269269
"""Return true if the header must contain beacon chain requests."""
270270
pass
271271

272+
@classmethod
273+
@abstractmethod
274+
def header_bal_hash_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
275+
"""Return true if the header must contain block access list hash."""
276+
pass
277+
272278
# Gas related abstract methods
273279

274280
@classmethod

src/ethereum_test_forks/forks/forks.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ def header_requests_required(cls, block_number: int = 0, timestamp: int = 0) ->
315315
"""At genesis, header must not contain beacon chain requests."""
316316
return False
317317

318+
@classmethod
319+
def header_bal_hash_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
320+
"""At genesis, header must not contain block access list hash."""
321+
return False
322+
318323
@classmethod
319324
def engine_new_payload_version(
320325
cls, block_number: int = 0, timestamp: int = 0
@@ -1808,6 +1813,20 @@ class BPO5(BPO4, bpo_fork=True):
18081813
pass
18091814

18101815

1816+
class Amsterdam(Osaka):
1817+
"""Amsterdam fork."""
1818+
1819+
@classmethod
1820+
def header_bal_hash_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
1821+
"""From Amsterdam, header must contain block access list hash (EIP-7928)."""
1822+
return True
1823+
1824+
@classmethod
1825+
def is_deployed(cls) -> bool:
1826+
"""Return True if this fork is deployed."""
1827+
return False
1828+
1829+
18111830
class EOFv1(Prague, solc_name="cancun"):
18121831
"""EOF fork."""
18131832

@@ -1837,12 +1856,3 @@ def is_deployed(cls) -> bool:
18371856
development.
18381857
"""
18391858
return False
1840-
1841-
1842-
class Amsterdam(Osaka):
1843-
"""Amsterdam fork."""
1844-
1845-
@classmethod
1846-
def is_deployed(cls) -> bool:
1847-
"""Return True if this fork is deployed."""
1848-
return False

0 commit comments

Comments
 (0)