Skip to content

Commit ef683b2

Browse files
authored
fix: use engine_newPayloadV5 for Glamsterdam (#2170)
* fix: use engine_newPayloadV5 for Amsterdam * fix: update exception mapper for geth * fix: We should update BAL hash in fixture for invalid tests * Clean up extraneous BAL exceptions * refactor: use fork check for BAL in engine payload
1 parent fea2f28 commit ef683b2

File tree

9 files changed

+85
-24
lines changed

9 files changed

+85
-24
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Test fixtures for use by clients are available for each release on the [Github r
2121

2222
- ✨ Add tighter validation for EIP-7928 model coming from t8n when filling ([#2138](https://github.com/ethereum/execution-spec-tests/pull/2138)).
2323
- ✨ Add flexible API for absence checks for EIP-7928 (BAL) tests ([#2124](https://github.com/ethereum/execution-spec-tests/pull/2124)).
24+
- 🐞 Use ``engine_newPayloadV5`` for `>=Amsterdam` forks in `consume engine` ([#2170](https://github.com/ethereum/execution-spec-tests/pull/2170)).
2425

2526
### 🧪 Test Cases
2627

src/ethereum_clis/clis/geth.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class GethExceptionMapper(ExceptionMapper):
7171
TransactionException.TYPE_4_TX_PRE_FORK: ("transaction type not supported"),
7272
TransactionException.INITCODE_SIZE_EXCEEDED: "max initcode size exceeded",
7373
TransactionException.NONCE_MISMATCH_TOO_LOW: "nonce too low",
74+
TransactionException.NONCE_MISMATCH_TOO_HIGH: "nonce too high",
7475
BlockException.INVALID_DEPOSIT_EVENT_LAYOUT: "unable to parse deposit data",
7576
BlockException.INCORRECT_BLOB_GAS_USED: "blob gas used mismatch",
7677
BlockException.INCORRECT_EXCESS_BLOB_GAS: "invalid excessBlobGas",
@@ -79,6 +80,9 @@ class GethExceptionMapper(ExceptionMapper):
7980
BlockException.SYSTEM_CONTRACT_CALL_FAILED: "system call failed to execute:",
8081
BlockException.INVALID_BLOCK_HASH: "blockhash mismatch",
8182
BlockException.RLP_BLOCK_LIMIT_EXCEEDED: "block RLP-encoded size exceeds maximum",
83+
BlockException.INVALID_BAL_EXTRA_ACCOUNT: "BAL change not reported in computed",
84+
BlockException.INVALID_BAL_MISSING_ACCOUNT: "additional mutations compared to BAL",
85+
BlockException.INVALID_BLOCK_ACCESS_LIST: "unequal",
8286
}
8387
mapping_regex: ClassVar[Dict[ExceptionBase, str]] = {
8488
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: (

src/ethereum_test_exceptions/exceptions/block.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,20 @@ class BlockException(ExceptionBase):
216216
Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but the layout
217217
of the event does not match the required layout.
218218
"""
219+
# --- Block-Level Access Lists (EIP-7928) --- #
220+
INVALID_BLOCK_ACCESS_LIST = auto()
221+
"""
222+
Block's access list is invalid.
223+
"""
224+
INVALID_BAL_HASH = auto()
225+
"""
226+
Block header's BAL hash does not match the computed BAL hash.
227+
"""
228+
INVALID_BAL_EXTRA_ACCOUNT = auto()
229+
"""
230+
Block BAL contains an account change that is not present in the computed BAL.
231+
"""
232+
INVALID_BAL_MISSING_ACCOUNT = auto()
233+
"""
234+
Block BAL is missing an account change that is present in the computed BAL.
235+
"""

src/ethereum_test_fixtures/blockchain.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,12 @@ def from_fixture_header(
301301
Hash,
302302
List[Bytes],
303303
]
304+
EngineNewPayloadV5Parameters = EngineNewPayloadV4Parameters
304305

305306
# Important: We check EngineNewPayloadV3Parameters first as it has more fields, and pydantic
306307
# has a weird behavior when the smaller tuple is checked first.
307308
EngineNewPayloadParameters = Union[
309+
EngineNewPayloadV5Parameters,
308310
EngineNewPayloadV4Parameters,
309311
EngineNewPayloadV3Parameters,
310312
EngineNewPayloadV1Parameters,
@@ -354,6 +356,13 @@ def from_fixture_header(
354356
)
355357

356358
assert new_payload_version is not None, "Invalid header for engine_newPayload"
359+
360+
if fork.engine_execution_payload_block_access_list(header.number, header.timestamp):
361+
if block_access_list is None:
362+
raise ValueError(
363+
f"`block_access_list` is required in engine `ExecutionPayload` for >={fork}."
364+
)
365+
357366
execution_payload = FixtureExecutionPayload.from_fixture_header(
358367
header=header,
359368
transactions=transactions,

src/ethereum_test_forks/base_fork.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,17 @@ def engine_new_payload_target_blobs_per_block(
553553
"""
554554
pass
555555

556+
@classmethod
557+
@abstractmethod
558+
def engine_execution_payload_block_access_list(
559+
cls, block_number: int = 0, timestamp: int = 0
560+
) -> bool:
561+
"""
562+
Return `True` if the engine api version requires execution payload to include a
563+
`block_access_list`.
564+
"""
565+
pass
566+
556567
@classmethod
557568
@abstractmethod
558569
def engine_payload_attribute_target_blobs_per_block(

src/ethereum_test_forks/forks/forks.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0)
347347
"""At genesis, payloads do not have requests."""
348348
return False
349349

350+
@classmethod
351+
def engine_execution_payload_block_access_list(
352+
cls, block_number: int = 0, timestamp: int = 0
353+
) -> bool:
354+
"""At genesis, payloads do not have block access list."""
355+
return False
356+
350357
@classmethod
351358
def engine_new_payload_target_blobs_per_block(
352359
cls,
@@ -1836,6 +1843,23 @@ def is_deployed(cls) -> bool:
18361843
"""Return True if this fork is deployed."""
18371844
return False
18381845

1846+
@classmethod
1847+
def engine_new_payload_version(
1848+
cls, block_number: int = 0, timestamp: int = 0
1849+
) -> Optional[int]:
1850+
"""From Amsterdam, new payload calls must use version 5."""
1851+
return 5
1852+
1853+
@classmethod
1854+
def engine_execution_payload_block_access_list(
1855+
cls, block_number: int = 0, timestamp: int = 0
1856+
) -> bool:
1857+
"""
1858+
From Amsterdam, engine execution payload includes `block_access_list` as
1859+
a parameter.
1860+
"""
1861+
return True
1862+
18391863

18401864
class EOFv1(Prague, solc_name="cancun"):
18411865
"""EOF fork."""

src/ethereum_test_specs/blockchain.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -629,12 +629,15 @@ def generate_block_data(
629629
header.fork = fork # Deleted during `apply` because `exclude=True`
630630

631631
# Process block access list - apply transformer if present for invalid tests
632-
bal = transition_tool_output.result.block_access_list
633-
if block.expected_block_access_list is not None and bal is not None:
634-
# Use to_fixture_bal to validate and potentially transform the BAL
635-
bal = block.expected_block_access_list.to_fixture_bal(bal)
636-
# Don't update the header hash - leave it as the hash of the correct BAL
637-
# This creates a mismatch that should cause the block to be rejected
632+
t8n_bal = transition_tool_output.result.block_access_list
633+
bal = t8n_bal
634+
if block.expected_block_access_list is not None and t8n_bal is not None:
635+
block.expected_block_access_list.verify_against(t8n_bal)
636+
637+
bal = block.expected_block_access_list.modify_if_invalid_test(t8n_bal)
638+
if bal != t8n_bal:
639+
# If the BAL was modified, update the header hash
640+
header.block_access_list_hash = Hash(bal.rlp.keccak256())
638641

639642
built_block = BuiltBlock(
640643
header=header,

src/ethereum_test_types/block_access_list/__init__.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,9 @@ def modify(
256256
new_instance._modifier = compose(*modifiers)
257257
return new_instance
258258

259-
def to_fixture_bal(self, t8n_bal: "BlockAccessList") -> "BlockAccessList":
259+
def modify_if_invalid_test(self, t8n_bal: "BlockAccessList") -> "BlockAccessList":
260260
"""
261-
Convert t8n BAL to fixture BAL, optionally applying transformations.
262-
263-
1. First validates expectations are met (if any)
264-
2. Then applies modifier if specified (for invalid tests)
261+
Apply the modifier to the given BAL if this is an invalid test case.
265262
266263
Args:
267264
t8n_bal: The BlockAccessList from t8n tool
@@ -270,13 +267,8 @@ def to_fixture_bal(self, t8n_bal: "BlockAccessList") -> "BlockAccessList":
270267
The potentially transformed BlockAccessList for the fixture
271268
272269
"""
273-
if self.account_expectations:
274-
self.verify_against(t8n_bal)
275-
276-
# Apply modifier if present (for invalid tests)
277270
if self._modifier:
278271
return self._modifier(t8n_bal)
279-
280272
return t8n_bal
281273

282274
def verify_against(self, actual_bal: "BlockAccessList") -> None:

tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def test_bal_invalid_missing_nonce(
7272
blocks=[
7373
Block(
7474
txs=[tx],
75-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
75+
exception=BlockException.INVALID_BLOCK_ACCESS_LIST,
7676
expected_block_access_list=BlockAccessListExpectation(
7777
account_expectations={
7878
sender: BalAccountExpectation(
@@ -111,7 +111,7 @@ def test_bal_invalid_nonce_value(
111111
blocks=[
112112
Block(
113113
txs=[tx],
114-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
114+
exception=BlockException.INVALID_BLOCK_ACCESS_LIST,
115115
expected_block_access_list=BlockAccessListExpectation(
116116
account_expectations={
117117
sender: BalAccountExpectation(
@@ -155,7 +155,7 @@ def test_bal_invalid_storage_value(
155155
blocks=[
156156
Block(
157157
txs=[tx],
158-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
158+
exception=BlockException.INVALID_BLOCK_ACCESS_LIST,
159159
expected_block_access_list=BlockAccessListExpectation(
160160
account_expectations={
161161
contract: BalAccountExpectation(
@@ -219,7 +219,7 @@ def test_bal_invalid_tx_order(
219219
blocks=[
220220
Block(
221221
txs=[tx1, tx2],
222-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
222+
exception=BlockException.INVALID_BLOCK_ACCESS_LIST,
223223
expected_block_access_list=BlockAccessListExpectation(
224224
account_expectations={
225225
sender1: BalAccountExpectation(
@@ -269,7 +269,7 @@ def test_bal_invalid_account(
269269
blocks=[
270270
Block(
271271
txs=[tx],
272-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
272+
exception=BlockException.INVALID_BAL_EXTRA_ACCOUNT,
273273
expected_block_access_list=BlockAccessListExpectation(
274274
account_expectations={
275275
sender: BalAccountExpectation(
@@ -412,7 +412,7 @@ def test_bal_invalid_complex_corruption(
412412
blocks=[
413413
Block(
414414
txs=[tx1, tx2],
415-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
415+
exception=BlockException.INVALID_BLOCK_ACCESS_LIST,
416416
expected_block_access_list=BlockAccessListExpectation(
417417
account_expectations={
418418
sender: BalAccountExpectation(
@@ -474,7 +474,7 @@ def test_bal_invalid_missing_account(
474474
blocks=[
475475
Block(
476476
txs=[tx],
477-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
477+
exception=BlockException.INVALID_BAL_MISSING_ACCOUNT,
478478
expected_block_access_list=BlockAccessListExpectation(
479479
account_expectations={
480480
sender: BalAccountExpectation(
@@ -516,7 +516,7 @@ def test_bal_invalid_balance_value(
516516
blocks=[
517517
Block(
518518
txs=[tx],
519-
exception=BlockException.INCORRECT_BLOCK_FORMAT,
519+
exception=BlockException.INVALID_BLOCK_ACCESS_LIST,
520520
expected_block_access_list=BlockAccessListExpectation(
521521
account_expectations={
522522
receiver: BalAccountExpectation(

0 commit comments

Comments
 (0)