Skip to content

Commit d206d4f

Browse files
authored
feat: add more invalid BAL test cases; extend invalid case coverage (#2653)
* feat: add more invalid BAL test cases; extend invalid case coverage * chore: align renames with test_cases.md * chore: align test_cases.md with implementations from audit * feat(tests): add missing / invalid coinbase BAL tests * chore: consolidate unused BAL exceptions * fix(tests): changes from comments on PR #2653 * fix(test,types): Fix bal_hash / block_access_list_hash mismatch for modifier * chore(test,types): If Header has a field and FixtureHeader doesn't, validate against this on apply
1 parent 132c09d commit d206d4f

11 files changed

Lines changed: 516 additions & 92 deletions

File tree

packages/testing/src/execution_testing/client_clis/clis/besu.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -457,20 +457,11 @@ class BesuExceptionMapper(ExceptionMapper):
457457
r"Blob transaction has too many blobs: \d+|"
458458
r"Invalid Blob Count: \d+"
459459
),
460-
# BAL Exceptions: TODO - review once all clients completed.
461-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
462-
r"Block access list hash mismatch, "
463-
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)|"
464-
r"Block access list validation failed for block 0x[a-f0-9]+"
465-
),
460+
# BAL Exceptions
466461
BlockException.INVALID_BAL_HASH: (
467462
r"Block access list hash mismatch, "
468463
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)"
469464
),
470-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
471-
r"Block access list hash mismatch, "
472-
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)"
473-
),
474465
BlockException.BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED: (
475466
r"Block access list validation failed for block 0x[a-f0-9]+"
476467
),

packages/testing/src/execution_testing/client_clis/clis/erigon.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,15 @@ class ErigonExceptionMapper(ExceptionMapper):
9494
BlockException.INVALID_STATE_ROOT: "invalid block: wrong trie root",
9595
BlockException.INVALID_RECEIPTS_ROOT: "receiptHash mismatch",
9696
BlockException.INVALID_LOG_BLOOM: "invalid bloom",
97-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
98-
"block access list mismatch"
99-
),
10097
BlockException.INCORRECT_BLOCK_FORMAT: "invalid block access list",
101-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: "invalid block access list",
10298
BlockException.GAS_USED_OVERFLOW: "block gas used overflow",
10399
}
104100
mapping_regex = {
105-
BlockException.INVALID_BLOCK_ACCESS_LIST: (
101+
BlockException.INVALID_BAL_HASH: (
106102
r"invalid block access list|block access list mismatch"
107103
),
108-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
109-
r"block access list mismatch"
110-
),
111-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
112-
r"invalid block access list"
104+
BlockException.INVALID_BLOCK_ACCESS_LIST: (
105+
r"invalid block access list|block access list mismatch"
113106
),
114107
BlockException.INCORRECT_BLOCK_FORMAT: (r"invalid block access list"),
115108
BlockException.BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED: (

packages/testing/src/execution_testing/client_clis/clis/ethrex.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ class EthrexExceptionMapper(ExceptionMapper):
4141
"Block access list hash does not match the one in "
4242
"the header after executing"
4343
),
44-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
45-
"Block access list hash does not match the one in "
46-
"the header after executing"
47-
),
48-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
49-
"Block access list hash does not match the one in "
50-
"the header after executing"
51-
),
5244
BlockException.INCORRECT_BLOCK_FORMAT: (
5345
"not in strictly ascending order for"
5446
),
@@ -175,20 +167,18 @@ class EthrexExceptionMapper(ExceptionMapper):
175167
BlockException.RLP_BLOCK_LIMIT_EXCEEDED: (
176168
r"Maximum block size exceeded.*"
177169
),
178-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
179-
r"Block access list accounts not in strictly ascending order.*|"
180-
r"BAL validation failed: account .* was never accessed.*"
181-
),
182-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (r"absent from BAL"),
170+
BlockException.INVALID_BAL_HASH: r"BAL validation failed",
183171
BlockException.INVALID_BLOCK_ACCESS_LIST: (
184172
r"Block access list contains index \d+ "
185173
r"exceeding max valid index \d+|"
186174
r"Failed to RLP decode BAL|"
187175
r"Block access list .+ not in strictly ascending order.*|"
188176
r"BAL validation failed for (tx \d+|system_tx|withdrawal): .*|"
189177
r"BAL validation failed: .*|"
178+
r"absent from BAL|"
190179
r"Block access list slot .+ is in both "
191-
r"storage_changes and storage_reads.*"
180+
r"storage_changes and storage_reads.*|"
181+
r"Invalid block hash"
192182
),
193183
BlockException.INCORRECT_BLOCK_FORMAT: (
194184
r"Block access list hash does not match "

packages/testing/src/execution_testing/client_clis/clis/geth.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,6 @@ class GethExceptionMapper(ExceptionMapper):
111111
BlockException.RLP_BLOCK_LIMIT_EXCEEDED: (
112112
"block RLP-encoded size exceeds maximum"
113113
),
114-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
115-
"BAL change not reported in computed"
116-
),
117-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
118-
"additional mutations compared to BAL"
119-
),
120114
BlockException.INVALID_BLOCK_ACCESS_LIST: "unequal",
121115
BlockException.INVALID_BASEFEE_PER_GAS: "invalid baseFee",
122116
BlockException.INVALID_BLOCK_TIMESTAMP_OLDER_THAN_PARENT: (
@@ -157,19 +151,17 @@ class GethExceptionMapper(ExceptionMapper):
157151
#
158152
# EELS definition for `is_valid_deposit_event_data`:
159153
# https://github.com/ethereum/execution-specs/blob/5ddb904fa7ba27daeff423e78466744c51e8cb6a/src/ethereum/forks/prague/requests.py#L51
160-
# BAL Exceptions: TODO - review once all clients completed.
161-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
162-
r"invalid block access list:"
163-
),
154+
# BAL Exceptions
164155
BlockException.INVALID_BAL_HASH: (r"invalid block access list:"),
165-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
166-
r"computed state diff contained mutated accounts "
167-
r"which weren't reported in BAL|"
168-
r"invalid block access list:"
169-
),
170156
BlockException.INVALID_BLOCK_ACCESS_LIST: (
171157
r"difference between computed state diff and "
172-
r"BAL entry for account|invalid block access list:"
158+
r"BAL entry for account|"
159+
r"invalid block access list:|"
160+
r"computed state diff contained mutated accounts "
161+
r"which weren't reported in BAL|"
162+
r"BAL change not reported in computed|"
163+
r"additional mutations compared to BAL|"
164+
r"[bB][aA][lL] validation fail"
173165
),
174166
BlockException.INCORRECT_BLOCK_FORMAT: (r"invalid block access list:"),
175167
BlockException.BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED: (

packages/testing/src/execution_testing/client_clis/clis/nethermind.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,15 +437,8 @@ class NethermindExceptionMapper(ExceptionMapper):
437437
# BAL Exceptions — specific exceptions have unique patterns, but
438438
# INVALID_BLOCK_ACCESS_LIST and INCORRECT_BLOCK_FORMAT intentionally
439439
# overlap because the test framework requires `want in got` matching.
440+
# BAL Exceptions
440441
BlockException.INVALID_BAL_HASH: (r"InvalidBlockLevelAccessListHash:"),
441-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
442-
r"InvalidBlockLevelAccessList:.*missing account"
443-
),
444-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
445-
r"InvalidBlockLevelAccessList:.*surplus changes"
446-
r"|could not be parsed as a block: "
447-
r"Error decoding block access list:"
448-
),
449442
BlockException.INVALID_BLOCK_ACCESS_LIST: (
450443
r"InvalidBlockLevelAccessListHash:"
451444
r"|InvalidBlockLevelAccessList:"

packages/testing/src/execution_testing/client_clis/clis/reth.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,8 @@ class RethExceptionMapper(ExceptionMapper):
109109
BlockException.GAS_USED_OVERFLOW: (
110110
r"transaction gas limit \w+ is more than blocks available gas \w+"
111111
),
112-
# BAL Exceptions: TODO - review once all clients completed.
113-
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
114-
r"block access list hash mismatch"
115-
),
112+
# BAL Exceptions
116113
BlockException.INVALID_BAL_HASH: (r"block access list hash mismatch"),
117-
BlockException.INVALID_BAL_MISSING_ACCOUNT: (
118-
r"block access list hash mismatch"
119-
),
120114
BlockException.INVALID_BLOCK_ACCESS_LIST: (
121115
r"block access list hash mismatch"
122116
),

packages/testing/src/execution_testing/exceptions/exceptions/block.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,6 @@ class BlockException(ExceptionBase):
177177
"""Block's access list is invalid."""
178178
INVALID_BAL_HASH = auto()
179179
"""Block header's BAL hash does not match the computed BAL hash."""
180-
INVALID_BAL_EXTRA_ACCOUNT = auto()
181-
"""
182-
Block BAL contains an account change that is not present in the computed
183-
BAL.
184-
"""
185-
INVALID_BAL_MISSING_ACCOUNT = auto()
186-
"""
187-
Block BAL is missing an account change that is present in the computed BAL.
188-
"""
189180
BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED = auto()
190181
"""
191182
Block access list exceeds the gas limit constraint (EIP-7928).

packages/testing/src/execution_testing/specs/blockchain.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class Header(CamelModel):
164164
excess_blob_gas: Removable | HexNumber | None = None
165165
parent_beacon_block_root: Removable | Hash | None = None
166166
requests_hash: Removable | Hash | None = None
167-
bal_hash: Removable | Hash | None = None
167+
block_access_list_hash: Removable | Hash | None = None
168168

169169
REMOVE_FIELD: ClassVar[Removable] = Removable()
170170
"""
@@ -216,12 +216,18 @@ def apply(self, target: FixtureHeader) -> FixtureHeader:
216216
"""
217217
Produce a fixture header copy with the set values from the modifier.
218218
"""
219-
return target.copy(
220-
**{
221-
k: (v if v is not Header.REMOVE_FIELD else None)
222-
for k, v in self.model_dump(exclude_none=True).items()
223-
}
224-
)
219+
overrides = {
220+
k: (v if v is not Header.REMOVE_FIELD else None)
221+
for k, v in self.model_dump(exclude_none=True).items()
222+
}
223+
unknown = overrides.keys() - target.__class__.model_fields.keys()
224+
if unknown:
225+
raise ValueError(
226+
f"Header fields {unknown} do not exist on "
227+
f"{target.__class__.__name__}. Check for field name "
228+
f"mismatches between Header and {target.__class__.__name__}."
229+
)
230+
return target.copy(**overrides)
225231

226232
def verify(self, target: FixtureHeader) -> None:
227233
"""Verify that the header fields from self are as expected."""
@@ -334,7 +340,9 @@ def set_environment(self, env: Environment) -> Environment:
334340
not isinstance(self.requests_hash, Removable)
335341
and self.block_access_list is not None
336342
):
337-
new_env_values["bal_hash"] = self.block_access_list.keccak256()
343+
new_env_values["block_access_list_hash"] = (
344+
self.block_access_list.keccak256()
345+
)
338346
new_env_values["block_access_list"] = self.block_access_list
339347
if (
340348
not isinstance(self.block_access_list, Removable)
@@ -723,11 +731,14 @@ def generate_block_data(
723731
"provided by the transition tool"
724732
)
725733

726-
computed_bal_hash = Hash(t8n_bal.rlp.keccak256())
727-
assert computed_bal_hash == header.block_access_list_hash, (
734+
computed_block_access_list_hash = Hash(t8n_bal.rlp.keccak256())
735+
assert (
736+
computed_block_access_list_hash
737+
== header.block_access_list_hash
738+
), (
728739
"Block access list hash in header does not match the "
729740
f"computed hash from BAL: {header.block_access_list_hash} "
730-
f"!= {computed_bal_hash}"
741+
f"!= {computed_block_access_list_hash}"
731742
)
732743

733744
if block.rlp_modifier is not None:

packages/testing/src/execution_testing/test_types/block_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def strip_computed_fields(cls, data: Any) -> Any:
142142
extra_data: Bytes = Field(Bytes(b"\x00"), exclude=True)
143143

144144
# EIP-7928: Block-level access lists
145-
bal_hash: Hash | None = Field(None)
145+
block_access_list_hash: Hash | None = Field(None)
146146
block_access_lists: Bytes | None = Field(None)
147147

148148
@computed_field # type: ignore[prop-decorator]

0 commit comments

Comments
 (0)