Skip to content

Commit 033c89f

Browse files
raxhvlfselmo
andauthored
✨ feat(tests): EIP-7928 No-op and adjacent test case (#2178)
* ✨ feat(tests): EIP-7928 test_bal_self_transfer * ✨ feat(tests): EIP-7928 test_bal_zero_value_transfer * ✨ feat(tests): EIP-7928 test_bal_self_transfer * 🚧 wip: noop reverts * 🚧 wip: noop reverts * 🚧 wip: aborted account access * 🥢 nit: * ✨ feat(tests): test_bal_fully_unmutated_account * fix: issues after rebase * feat: Use `BalAccountExpectation.empty()` for explicit empty checks * refactor: remove duplicate test for BAL noop * chore: move noop tests into main bal test file * chore: add changelog entry * 🥢 nit: Add call value * feat: add back unmutated test with explicit no balance change check --------- Co-authored-by: raxhvl <[email protected]> Co-authored-by: fselmo <[email protected]>
1 parent 0751556 commit 033c89f

File tree

6 files changed

+381
-31
lines changed

6 files changed

+381
-31
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Test fixtures for use by clients are available for each release on the [Github r
4141
- ✨ Add essential tests for coverage gaps in EIP-7951 (`p256verify` precompile) ([#2179](https://github.com/ethereum/execution-spec-tests/pull/2159), [#2203](https://github.com/ethereum/execution-spec-tests/pull/2203), [#2215](https://github.com/ethereum/execution-spec-tests/pull/2215), [#2216](https://github.com/ethereum/execution-spec-tests/pull/2216), [#2217](https://github.com/ethereum/execution-spec-tests/pull/2217), [#2218](https://github.com/ethereum/execution-spec-tests/pull/2218), [#2221](https://github.com/ethereum/execution-spec-tests/pull/2221), [#2229](https://github.com/ethereum/execution-spec-tests/pull/2229), [#2230](https://github.com/ethereum/execution-spec-tests/pull/2230), [#2237](https://github.com/ethereum/execution-spec-tests/pull/2237), [#2238](https://github.com/ethereum/execution-spec-tests/pull/2238)).
4242
- ✨ Add EIP-7928 successful and OOG single-opcode tests ([#2118](https://github.com/ethereum/execution-spec-tests/pull/2118)).
4343
- ✨ Add EIP-7928 tests for EIP-2930 interactions ([#2167](https://github.com/ethereum/execution-spec-tests/pull/2167)).
44+
- ✨ Add EIP-7928 tests for NOOP operations ([#2178](https://github.com/ethereum/execution-spec-tests/pull/2178)).
4445

4546
## [v5.0.0](https://github.com/ethereum/execution-spec-tests/releases/tag/v5.0.0) - 2025-09-05
4647

src/ethereum_test_types/block_access_list/expectations.py

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
BAL values in tests.
66
"""
77

8-
from typing import Any, Callable, Dict, List, Optional
8+
from typing import Any, Callable, ClassVar, Dict, List, Optional
99

1010
from pydantic import Field, PrivateAttr
1111

@@ -53,6 +53,33 @@ class BalAccountExpectation(CamelModel):
5353
default=None, description="Explicit absent value expectations using BalAccountAbsentValues"
5454
)
5555

56+
_EMPTY: ClassVar[Optional["BalAccountExpectation"]] = None
57+
58+
@classmethod
59+
def empty(cls) -> "BalAccountExpectation":
60+
"""
61+
Create an expectation that validates the account has NO changes.
62+
63+
This is distinct from `BalAccountExpectation()` with no fields set,
64+
which is ambiguous and clashes with `model_fields_set` logic, and
65+
will raise a clarifying error if used in expectations.
66+
67+
Returns:
68+
A BalAccountExpectation instance with all change lists empty.
69+
This uses a classvar to facilitate identity checks across
70+
multiple expectation instances.
71+
72+
"""
73+
if cls._EMPTY is None:
74+
cls._EMPTY = cls(
75+
nonce_changes=[],
76+
balance_changes=[],
77+
code_changes=[],
78+
storage_changes=[],
79+
storage_reads=[],
80+
)
81+
return cls._EMPTY
82+
5683

5784
def compose(
5885
*modifiers: Callable[["BlockAccessList"], "BlockAccessList"],
@@ -168,20 +195,29 @@ def verify_against(self, actual_bal: "BlockAccessList") -> None:
168195
raise BlockAccessListValidationError(
169196
f"Address {address} should not be in BAL but was found"
170197
)
171-
elif expectation == BalAccountExpectation():
172-
# explicit check for NO account changes for the address
173-
if actual_accounts_by_addr.get(address) != BalAccountChange(address=address):
174-
raise BlockAccessListValidationError(
175-
f"No account changes expected for {address} but found "
176-
f"changes: {actual_accounts_by_addr[address]}"
177-
)
198+
elif not expectation.model_fields_set:
199+
# Disallow ambiguous BalAccountExpectation() with no fields set
200+
raise BlockAccessListValidationError(
201+
f"Address {address}: BalAccountExpectation() with no fields set is "
202+
f"ambiguous. Use BalAccountExpectation.empty() to validate no changes, "
203+
f"or explicitly set the fields to validate "
204+
f"(e.g., nonce_changes=[...])."
205+
)
178206
else:
179207
# check address is present and validate changes
180208
if address not in actual_accounts_by_addr:
181209
raise BlockAccessListValidationError(
182210
f"Expected address {address} not found in actual BAL"
183211
)
184212

213+
if expectation is BalAccountExpectation.empty():
214+
# explicit check for "no changes" validation w/ .empty()
215+
if actual_accounts_by_addr.get(address) != BalAccountChange(address=address):
216+
raise BlockAccessListValidationError(
217+
f"No account changes expected for {address} but found "
218+
f"changes: {actual_accounts_by_addr[address]}"
219+
)
220+
185221
actual_account = actual_accounts_by_addr[address]
186222
try:
187223
self._compare_account_expectations(expectation, actual_account)

src/ethereum_test_types/tests/test_block_access_lists.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,18 @@ def test_address_exclusion_validation_raises_when_address_is_present():
6969
expectation.verify_against(actual_bal)
7070

7171

72-
def test_empty_account_changes_raises_when_changes_are_present():
72+
@pytest.mark.parametrize(
73+
"empty_changes_definition,exception_message",
74+
[
75+
[BalAccountExpectation(), "ambiguous. Use BalAccountExpectation.empty()"],
76+
[BalAccountExpectation.empty(), "No account changes expected for "],
77+
],
78+
ids=["BalAccountExpectation()", "BalAccountExpectation.empty()"],
79+
)
80+
def test_empty_account_changes_definitions(
81+
empty_changes_definition,
82+
exception_message,
83+
):
7384
"""
7485
Test that validation fails when expected empty changes but actual
7586
has changes.
@@ -85,12 +96,11 @@ def test_empty_account_changes_raises_when_changes_are_present():
8596
]
8697
)
8798

88-
expectation = BlockAccessListExpectation(account_expectations={alice: BalAccountExpectation()})
99+
expectation = BlockAccessListExpectation(
100+
account_expectations={alice: empty_changes_definition}
101+
)
89102

90-
with pytest.raises(
91-
BlockAccessListValidationError,
92-
match=f"No account changes expected for {alice}",
93-
):
103+
with pytest.raises(BlockAccessListValidationError, match=exception_message):
94104
expectation.verify_against(actual_bal)
95105

96106

0 commit comments

Comments
 (0)