-
Notifications
You must be signed in to change notification settings - Fork 169
feat(tests): Support for EIP-7928 - Block-Level Access Lists #2067
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
208256f
ab00c0a
3238667
0c43e3f
b1a9d2f
bfaba98
7489c35
5dbd10b
a5059e7
907bb72
674dc25
b0c8bd2
06464af
d583ef8
43b5549
6a4e6bb
9bb02f7
d9b2550
eb66f67
1fe330b
07f4013
89f38b2
9eb95ab
95eb661
f8eaee7
41f0ed5
38b6dbf
c6055af
d0eb106
8570378
e0c2fba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,6 +52,7 @@ | |
from ethereum_test_fixtures.common import FixtureBlobSchedule | ||
from ethereum_test_forks import Fork | ||
from ethereum_test_types import Alloc, Environment, Removable, Requests, Transaction, Withdrawal | ||
from ethereum_test_types.block_access_list import BlockAccessList, BlockAccessListExpectation | ||
|
||
from .base import BaseTest, OpMode, verify_result | ||
from .debugging import print_traces | ||
|
@@ -121,6 +122,7 @@ class Header(CamelModel): | |
excess_blob_gas: Removable | HexNumber | None = None | ||
parent_beacon_block_root: Removable | Hash | None = None | ||
requests_hash: Removable | Hash | None = None | ||
bal_hash: Removable | Hash | None = None | ||
|
||
REMOVE_FIELD: ClassVar[Removable] = Removable() | ||
""" | ||
|
@@ -206,6 +208,10 @@ class Block(Header): | |
An RLP modifying header which values would be used to override the ones | ||
returned by the `ethereum_clis.TransitionTool`. | ||
""" | ||
expected_block_access_list: BlockAccessListExpectation | None = None | ||
""" | ||
If set, the block access list will be verified and potentially corrupted for invalid tests. | ||
""" | ||
exception: BLOCK_EXCEPTION_TYPE = None | ||
""" | ||
If set, the block is expected to be rejected by the client. | ||
|
@@ -240,6 +246,10 @@ class Block(Header): | |
""" | ||
Post state for verification after block execution in BlockchainTest | ||
""" | ||
block_access_list: Bytes | None = Field(None) | ||
""" | ||
EIP-7928: Block-level access lists (serialized). | ||
""" | ||
|
||
def set_environment(self, env: Environment) -> Environment: | ||
""" | ||
|
@@ -269,6 +279,14 @@ def set_environment(self, env: Environment) -> Environment: | |
new_env_values["blob_gas_used"] = self.blob_gas_used | ||
if not isinstance(self.parent_beacon_block_root, Removable): | ||
new_env_values["parent_beacon_block_root"] = self.parent_beacon_block_root | ||
if not isinstance(self.requests_hash, Removable) and self.block_access_list is not None: | ||
new_env_values["bal_hash"] = self.block_access_list.keccak256() | ||
new_env_values["block_access_list"] = self.block_access_list | ||
if ( | ||
not isinstance(self.block_access_list, Removable) | ||
and self.block_access_list is not None | ||
): | ||
new_env_values["block_access_list"] = self.block_access_list | ||
""" | ||
These values are required, but they depend on the previous environment, | ||
so they can be calculated here. | ||
|
@@ -308,6 +326,7 @@ class BuiltBlock(CamelModel): | |
expected_exception: BLOCK_EXCEPTION_TYPE = None | ||
engine_api_error_code: EngineAPIError | None = None | ||
fork: Fork | ||
block_access_list: BlockAccessList | None | ||
|
||
def get_fixture_block(self) -> FixtureBlock | InvalidFixtureBlock: | ||
"""Get a FixtureBlockBase from the built block.""" | ||
|
@@ -319,6 +338,7 @@ def get_fixture_block(self) -> FixtureBlock | InvalidFixtureBlock: | |
if self.withdrawals is not None | ||
else None | ||
), | ||
block_access_list=self.block_access_list.rlp if self.block_access_list else None, | ||
fork=self.fork, | ||
).with_rlp(txs=self.txs) | ||
|
||
|
@@ -349,6 +369,7 @@ def get_fixture_engine_new_payload(self) -> FixtureEngineNewPayload: | |
requests=self.requests, | ||
validation_error=self.expected_exception, | ||
error_code=self.engine_api_error_code, | ||
block_access_list=self.block_access_list.rlp if self.block_access_list else None, | ||
) | ||
|
||
def verify_transactions(self, transition_tool_exceptions_reliable: bool) -> List[int]: | ||
|
@@ -585,12 +606,34 @@ def generate_block_data( | |
header.requests_hash = Hash(Requests(requests_lists=list(block.requests))) | ||
requests_list = block.requests | ||
|
||
if fork.header_bal_hash_required(header.number, 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. | ||
header = block.rlp_modifier.apply(header) | ||
header.fork = fork # Deleted during `apply` because `exclude=True` | ||
|
||
# Process block access list - apply transformer if present for invalid tests | ||
bal = transition_tool_output.result.block_access_list | ||
if block.expected_block_access_list is not None and bal is not None: | ||
# Use to_fixture_bal to validate and potentially transform the BAL | ||
bal = block.expected_block_access_list.to_fixture_bal(bal) | ||
# Don't update the header hash - leave it as the hash of the correct BAL | ||
# This creates a mismatch that should cause the block to be rejected | ||
Comment on lines
+634
to
+635
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice. One thing to consider is that when we test this as a Blockchain Engine type of test, potentially the exception is going to change, since we cannot influence the header from the payload we deliver via the Engine API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm yeah, good point. I'm just now starting to explore this for BAL. Not sure if we want to tackle this further down the line. Should we maybe put together some items to think about for BAL as an issue so we can track them while we iterate and try to get this consolidated for a merge? Let me know. |
||
|
||
built_block = BuiltBlock( | ||
header=header, | ||
alloc=transition_tool_output.alloc, | ||
|
@@ -603,6 +646,7 @@ def generate_block_data( | |
expected_exception=block.exception, | ||
engine_api_error_code=block.engine_api_error_code, | ||
fork=fork, | ||
block_access_list=bal, | ||
) | ||
|
||
try: | ||
|
@@ -614,14 +658,20 @@ def generate_block_data( | |
and block.rlp_modifier is None | ||
and block.requests is None | ||
and not block.skip_exception_verification | ||
and not ( | ||
block.expected_block_access_list is not None | ||
and block.expected_block_access_list.modifier is not None | ||
) | ||
): | ||
# Only verify block level exception if: | ||
# - No transaction exception was raised, because these are not reported as block | ||
# exceptions. | ||
# - No RLP modifier was specified, because the modifier is what normally | ||
# produces the block exception. | ||
# - No requests were specified, because modified requests are also what normally | ||
# produces the block exception. | ||
# - No transaction exception was raised, because these are not | ||
# reported as block exceptions. | ||
# - No RLP modifier was specified, because the modifier is what | ||
# normally produces the block exception. | ||
# - No requests were specified, because modified requests are also | ||
# what normally produces the block exception. | ||
# - No BAL modifier was specified, because modified BAL also | ||
# produces block exceptions. | ||
built_block.verify_block_exception( | ||
transition_tool_exceptions_reliable=t8n.exception_mapper.reliable, | ||
) | ||
|
@@ -683,6 +733,9 @@ def make_fixture( | |
last_block=i == len(self.blocks) - 1, | ||
) | ||
fixture_blocks.append(built_block.get_fixture_block()) | ||
|
||
# BAL verification already done in to_fixture_bal() if expected_block_access_list set | ||
|
||
if block.exception is None: | ||
# Update env, alloc and last block hash for the next block. | ||
alloc = built_block.alloc | ||
|
Uh oh!
There was an error while loading. Please reload this page.