Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e597ce3
feat(spec-specs): create Amsterdam from Osaka
fselmo Dec 8, 2025
2a2d0d5
fix(spec-tools): Fix lint by adding TODO docstring for Amsterdam init
fselmo Dec 9, 2025
3113f47
feat(specs): Implement EIP-7928: Block-Level Access Lists
fselmo Nov 11, 2025
dfce10d
fix(specs): Fix zero value withdrawals BAL tracking (#29)
fselmo Oct 30, 2025
468e75e
fix(specs): static upfront check for create + selfdestruct (#22)
nerolation Oct 30, 2025
c6df0b6
feat(tests): Implement more EIP-7928 tests
raxhvl Oct 29, 2025
6da8a02
fix(specs): Ensure tracking before first access (#1722)
nerolation Oct 31, 2025
743b06d
chore(tests): fill all tests for bal releases
fselmo Nov 3, 2025
3b17eb1
fix(spec-specs): duplicate storage writes in state tracker (#1743)
fselmo Nov 4, 2025
c7f83a3
fix(test-specs): validate t8n BAL independent of expectation existenc…
fselmo Nov 13, 2025
5f0e971
feat(specs): EIP-7928 refactoring
nerolation Nov 5, 2025
6c9ec93
fix(spec-specs): require and use blockenv for state tracking
fselmo Nov 5, 2025
0fc2f69
refactor(spec-specs): track BAL changes via frames
fselmo Nov 6, 2025
6aae4bb
fix(spec-specs): Mark original addr warm before delegation
fselmo Nov 11, 2025
338e733
fix(spec-specs): Make sure we account for no changes
fselmo Nov 11, 2025
e405848
fix(spec-specs): Better tracking for code changes; ensure with BAL test
fselmo Nov 12, 2025
bc46e65
fix(spec-specs): Use child frame for create message
fselmo Nov 12, 2025
40e7acc
fix(spec-specs): Normalize transaction before merging to block frame
fselmo Nov 12, 2025
c9851e1
fix(spec-specs): Early static check for SSTORE before any reads
fselmo Nov 12, 2025
1d9bf1f
fix(spec-specs): Track storage writes more appropriately wrt index
fselmo Nov 13, 2025
42def64
fix(spec-specs): Use functions, not methods; fix create revert
fselmo Nov 13, 2025
362e01a
fix(spec-specs): Default code to b"" in tracker, skip empty setting
fselmo Nov 14, 2025
05c122e
fix(spec-specs): Fix BAL cross-transaction tracking and nonce dedup
fselmo Nov 14, 2025
8ceade2
fix(spec-specs): Move destroy_account before BAL normalization
fselmo Nov 14, 2025
5a4a373
fix(spec-specs): Check delegation access gas before reading
fselmo Nov 14, 2025
dc01c2f
fix(spec-specs): Track code per auth; filter pre at tx frame
fselmo Nov 15, 2025
7f42477
fix(spec-specs): Use proper frames for system transactions
fselmo Nov 16, 2025
6ece1e5
fix(spec-specs): Track address at init collision
fselmo Nov 21, 2025
6c1d971
chore(spec-specs): Add Amsterdam docstring; update prepare msg
fselmo Nov 21, 2025
775cb9a
chore: Add pre-amsterdam BAL tests to doc for tracking
fselmo Nov 21, 2025
635edd8
fix(spec-specs): Calculate all gas we can before accessing state
fselmo Nov 24, 2025
39ed8c3
fix(test-tools): Remove named forks from blobSchedule; turn off BPOs
fselmo Nov 25, 2025
2b6e4d6
fix: add bal exception for erigon (#1809)
felix314159 Nov 26, 2025
3d65d6f
feat(test): Better describe the BAL for selfdestruct revert
fselmo Nov 26, 2025
c45d6b8
test(eip7928): add EXTCODECOPY OOG memory expansion BAL test
qu0b Nov 30, 2025
1364138
refactor(test-tests): parametrize existing test oog case instead
fselmo Dec 1, 2025
0a60532
test(eip7928): add cross-block precompile state leak test
qu0b Dec 1, 2025
7f73c1a
refactor(test-tests): Add BAL expectation to state leak test; fix lint
fselmo Dec 1, 2025
796c505
eip7928: add SELFDESTRUCT OOG BAL test
qu0b Dec 4, 2025
70d6f71
refactor(tests): move selfdestruct bal tests to oog file; add gas bou…
fselmo Dec 4, 2025
7fc5d4d
update test_cases.md
fselmo Dec 5, 2025
14f8d34
feat(tests): Port oog create refund test; add BAL >= Amsterdam
fselmo Dec 1, 2025
402d813
refactor(spec-specs): Refactor state changes and frame hierarchy (#1841)
fselmo Dec 8, 2025
b6c9410
fix(spec,tests): Change BAL to List[AccountChange] (#1844)
gurukamath Dec 8, 2025
051adb0
fix mkdocs
fselmo Dec 8, 2025
8882960
Qu0b/add bal test cases (#1812)
qu0b Dec 8, 2025
a0c8747
feat(test-tests): BAL test for nested storage write reset same tx (#1…
fselmo Dec 8, 2025
6044b67
fix(spec-specs): Fix issues after rebasing with forks/osaka
fselmo Dec 9, 2025
dd3a353
fix(spec-specs): post-exec net-zero filtering post specs refactor
fselmo Dec 9, 2025
3a85f3d
refactor(spec-specs): Move net-zero filtering inside commit tx frame
fselmo Dec 9, 2025
d0726cc
enable BPO1 and BPO2 for Amsterdam
qu0b Dec 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/configs/feature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ benchmark_fast:

bal:
evm-type: develop
fill-params: --fork=Amsterdam ./tests/amsterdam/eip7928_block_level_access_lists
# TODO: Turn on block rlp limit tests after making filling them more flexible.
fill-params: --fork=Amsterdam -k "not eip7934"
feature_only: true
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Test fixtures for use by clients are available for each release on the [Github r
### 📋 Misc

- 🐞 WELDed the EEST tox environments relevant to producing documentation into EELS, and added a tool to cleanly add codespell whitelist entries. ([#1695](https://github.com/ethereum/execution-specs/pull/1659)).
- 🐞 Fix duplicate storage write issues for block access lists EIP-7928 implementation ([#1743](https://github.com/ethereum/execution-specs/pull/1743)).

### 🧪 Test Cases

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ def get_blob_schedule_entries(fork: Fork) -> Dict[str, int]:
"HIVE_CANCUN_TIMESTAMP": 0,
"HIVE_PRAGUE_TIMESTAMP": 0,
"HIVE_OSAKA_TIMESTAMP": 0,
**get_blob_schedule_entries(Osaka),
},
PragueToOsakaAtTime15k: {
"HIVE_FORK_HOMESTEAD": 0,
Expand All @@ -314,7 +313,6 @@ def get_blob_schedule_entries(fork: Fork) -> Dict[str, int]:
"HIVE_CANCUN_TIMESTAMP": 0,
"HIVE_PRAGUE_TIMESTAMP": 0,
"HIVE_OSAKA_TIMESTAMP": 15000,
**get_blob_schedule_entries(Osaka),
},
BPO1: {
"HIVE_FORK_HOMESTEAD": 0,
Expand Down Expand Up @@ -498,9 +496,6 @@ def get_blob_schedule_entries(fork: Fork) -> Dict[str, int]:
"HIVE_OSAKA_TIMESTAMP": 0,
"HIVE_BPO1_TIMESTAMP": 0,
"HIVE_BPO2_TIMESTAMP": 0,
"HIVE_BPO3_TIMESTAMP": 0,
"HIVE_BPO4_TIMESTAMP": 0,
"HIVE_AMSTERDAM_TIMESTAMP": 0,
**get_blob_schedule_entries(Amsterdam),
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class ErigonExceptionMapper(ExceptionMapper):
BlockException.INVALID_LOG_BLOOM: "invalid bloom",
}
mapping_regex = {
BlockException.INVALID_BLOCK_ACCESS_LIST: r"invalid block access list|block access list mismatch",
TransactionException.GAS_LIMIT_EXCEEDS_MAXIMUM: (
r"invalid block, txnIdx=\d+,.*gas limit too high"
),
Expand Down
16 changes: 16 additions & 0 deletions packages/testing/src/execution_testing/fixtures/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ class FixtureHeader(CamelModel):
requests_hash: (
Annotated[Hash, HeaderForkRequirement("requests")] | None
) = Field(None)
block_access_list_hash: (
Annotated[Hash, HeaderForkRequirement("bal_hash")] | None
) = Field(None, alias="blockAccessListHash")

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

Expand Down Expand Up @@ -283,6 +286,11 @@ def genesis(cls, fork: Fork, env: Environment, state_root: Hash) -> Self:
"requests_hash": Requests()
if fork.header_requests_required(block_number=0, timestamp=0)
else None,
"block_access_list_hash": (
BlockAccessList().rlp_hash
if fork.header_bal_hash_required(block_number=0, timestamp=0)
else None
),
"fork": fork,
}
return cls(**environment_values, **extras)
Expand Down Expand Up @@ -408,6 +416,14 @@ def from_fixture_header(
"Invalid header for engine_newPayload"
)

if fork.engine_execution_payload_block_access_list(
block_number=header.number, timestamp=header.timestamp
):
if block_access_list is None:
raise ValueError(
f"`block_access_list` is required in engine `ExecutionPayload` for >={fork}."
)

execution_payload = FixtureExecutionPayload.from_fixture_header(
header=header,
transactions=transactions,
Expand Down
19 changes: 19 additions & 0 deletions packages/testing/src/execution_testing/forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,14 @@ def header_requests_required(
"""Return true if the header must contain beacon chain requests."""
pass

@classmethod
@abstractmethod
def header_bal_hash_required(
cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
"""Return true if the header must contain block access list hash."""
pass

# Gas related abstract methods

@classmethod
Expand Down Expand Up @@ -710,6 +718,17 @@ def engine_new_payload_target_blobs_per_block(
"""
pass

@classmethod
@abstractmethod
def engine_execution_payload_block_access_list(
cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Return `True` if the engine api version requires execution payload to
include a `block_access_list`.
"""
pass

@classmethod
@abstractmethod
def engine_payload_attribute_target_blobs_per_block(
Expand Down
37 changes: 37 additions & 0 deletions packages/testing/src/execution_testing/forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,14 @@ def header_requests_required(
del block_number, timestamp
return False

@classmethod
def header_bal_hash_required(
cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
"""At genesis, header must not contain block access list hash."""
del block_number, timestamp
return False

@classmethod
def engine_new_payload_version(
cls, *, block_number: int = 0, timestamp: int = 0
Expand Down Expand Up @@ -483,6 +491,14 @@ def engine_new_payload_requests(
del block_number, timestamp
return False

@classmethod
def engine_execution_payload_block_access_list(
cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
"""At genesis, payloads do not have block access list."""
del block_number, timestamp
return False

@classmethod
def engine_new_payload_target_blobs_per_block(
cls,
Expand Down Expand Up @@ -2462,6 +2478,16 @@ class BPO5(BPO4, bpo_fork=True):
class Amsterdam(Osaka):
"""Amsterdam fork."""

@classmethod
def header_bal_hash_required(
cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
From Amsterdam, header must contain block access list hash (EIP-7928).
"""
del block_number, timestamp
return True

@classmethod
def is_deployed(cls) -> bool:
"""Return True if this fork is deployed."""
Expand All @@ -2475,6 +2501,17 @@ def engine_new_payload_version(
del block_number, timestamp
return 5

@classmethod
def engine_execution_payload_block_access_list(
cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
From Amsterdam, engine execution payload includes `block_access_list`
as a parameter.
"""
del block_number, timestamp
return True


class EOFv1(Prague, solc_name="cancun"):
"""EOF fork."""
Expand Down
48 changes: 47 additions & 1 deletion packages/testing/src/execution_testing/specs/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,11 +551,16 @@ def make_genesis(
state_root = pre_alloc.state_root()
genesis = FixtureHeader.genesis(self.fork, env, state_root)

genesis_bal = None
if self.fork.header_bal_hash_required(block_number=0, timestamp=0):
genesis_bal = BlockAccessList()

return (
pre_alloc,
FixtureBlockBase(
header=genesis,
withdrawals=None if env.withdrawals is None else [],
block_access_list=genesis_bal,
).with_rlp(txs=[]),
)

Expand Down Expand Up @@ -687,6 +692,24 @@ def generate_block_data(
)
requests_list = block.requests

if self.fork.header_bal_hash_required(
block_number=header.number, timestamp=header.timestamp
):
assert (
transition_tool_output.result.block_access_list is not None
), (
"Block access list is required for this block but was not provided "
"by the transition tool"
)

rlp = transition_tool_output.result.block_access_list.rlp
computed_bal_hash = Hash(rlp.keccak256())
assert computed_bal_hash == header.block_access_list_hash, (
"Block access list hash in header does not match the "
f"computed hash from BAL: {header.block_access_list_hash} "
f"!= {computed_bal_hash}"
)

if block.rlp_modifier is not None:
# Modify any parameter specified in the `rlp_modifier` after
# transition tool processing.
Expand All @@ -695,6 +718,29 @@ def generate_block_data(
self.fork
) # Deleted during `apply` because `exclude=True`

# Process block access list - apply transformer if present for invalid
# tests
t8n_bal = transition_tool_output.result.block_access_list
bal = t8n_bal

# Always validate BAL structural integrity (ordering, duplicates) if present
if t8n_bal is not None:
t8n_bal.validate_structure()

# If expected BAL is defined, verify against it
if (
block.expected_block_access_list is not None
and t8n_bal is not None
):
block.expected_block_access_list.verify_against(t8n_bal)

bal = block.expected_block_access_list.modify_if_invalid_test(
t8n_bal
)
if bal != t8n_bal:
# If the BAL was modified, update the header hash
header.block_access_list_hash = Hash(bal.rlp.keccak256())

built_block = BuiltBlock(
header=header,
alloc=transition_tool_output.alloc,
Expand All @@ -708,7 +754,7 @@ def generate_block_data(
expected_exception=block.exception,
engine_api_error_code=block.engine_api_error_code,
fork=self.fork,
block_access_list=None,
block_access_list=bal,
)

try:
Expand Down
Loading
Loading