Skip to content

feature: Add engine API forkchoice updated information in fixtures #256

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

Merged
merged 3 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int =
"""
pass

@classmethod
@abstractmethod
def engine_forkchoice_updated_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
Returns `None` if the forks canonical chain cannot be set using the forkchoice method.
"""
pass

# Meta information about the fork
@classmethod
def name(cls) -> str:
Expand Down
9 changes: 9 additions & 0 deletions src/ethereum_test_forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int =
"""
return False

@classmethod
def engine_forkchoice_updated_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
At genesis, forkchoice updates cannot be sent through the engine API.
"""
return cls.engine_new_payload_version(block_number, timestamp)

@classmethod
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
Expand Down
5 changes: 5 additions & 0 deletions src/ethereum_test_tools/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,11 @@ class Fixture:
to_json=True,
),
)
fcu_version: Optional[int] = field(
json_encoder=JSONEncoder.Field(
name="engineFcuVersion",
),
)
genesis: FixtureHeader = field(
json_encoder=JSONEncoder.Field(
name="genesisBlockHeader",
Expand Down
3 changes: 2 additions & 1 deletion src/ethereum_test_tools/filling/fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def fill_test(

pre, genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)

(blocks, head, alloc) = test_spec.make_blocks(
(blocks, head, alloc, fcu_version) = test_spec.make_blocks(
t8n,
genesis,
pre,
Expand All @@ -45,6 +45,7 @@ def fill_test(
post_state=alloc_to_accounts(alloc),
seal_engine=engine,
name=test_spec.tag,
fcu_version=fcu_version,
)
fixture.fill_info(t8n, spec)

Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_test_tools/spec/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def make_blocks(
fork: Fork,
chain_id: int = 1,
eips: Optional[List[int]] = None,
) -> Tuple[List[FixtureBlock], Hash, Dict[str, Any]]:
) -> Tuple[List[FixtureBlock], Hash, Dict[str, Any], Optional[int]]:
"""
Generate the blockchain that must be executed sequentially during test.
"""
Expand Down
15 changes: 13 additions & 2 deletions src/ethereum_test_tools/spec/blockchain_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def make_blocks(
fork: Fork,
chain_id=1,
eips: Optional[List[int]] = None,
) -> Tuple[List[FixtureBlock], Hash, Dict[str, Any]]:
) -> Tuple[List[FixtureBlock], Hash, Dict[str, Any], Optional[int]]:
"""
Create a block list from the blockchain test definition.
Performs checks against the expected behavior of the test.
Expand All @@ -273,6 +273,9 @@ def make_blocks(
alloc = to_json(pre)
env = Environment.from_parent_header(genesis)
blocks: List[FixtureBlock] = []
fcu_version: Optional[int] = None
last_valid: Optional[FixtureHeader] = None

head = genesis.hash if genesis.hash is not None else Hash(0)
for block in self.blocks:
fixture_block, env, alloc, head = self.make_block(
Expand All @@ -286,14 +289,22 @@ def make_blocks(
eips=eips,
)
blocks.append(fixture_block)
if block.exception is None:
last_valid = fixture_block.block_header

if not self.base_test_config.disable_hive and last_valid is not None:
fcu_version = fork.engine_forkchoice_updated_version(
block_number=last_valid.number,
timestamp=last_valid.timestamp,
)

try:
verify_post_alloc(self.post, alloc)
except Exception as e:
print_traces(t8n.get_traces())
raise e

return (blocks, head, alloc)
return (blocks, head, alloc, fcu_version)


BlockchainTestSpec = Callable[[str], Generator[BlockchainTest, None, None]]
Expand Down
8 changes: 6 additions & 2 deletions src/ethereum_test_tools/spec/state_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def make_blocks(
fork: Fork,
chain_id=1,
eips: Optional[List[int]] = None,
) -> Tuple[List[FixtureBlock], Hash, Dict[str, Any]]:
) -> Tuple[List[FixtureBlock], Hash, Dict[str, Any], Optional[int]]:
"""
Create a block from the state test definition.
Performs checks against the expected behavior of the test.
Expand Down Expand Up @@ -178,15 +178,18 @@ def make_blocks(
withdrawals=env.withdrawals,
)

# Hive specific fields
new_payload: FixtureEngineNewPayload | None = None
fcu_version: int | None = None
if not self.base_test_config.disable_hive:
new_payload = FixtureEngineNewPayload.from_fixture_header(
fork=fork,
header=header,
transactions=txs,
withdrawals=env.withdrawals,
error_code=self.engine_api_error_code,
error_code=None,
)
fcu_version = fork.engine_forkchoice_updated_version(header.number, header.timestamp)

return (
[
Expand All @@ -201,6 +204,7 @@ def make_blocks(
],
header.hash,
alloc,
fcu_version,
)


Expand Down
1 change: 1 addition & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ extcodesize
fn
fname
forkchoice
fcu
formatOnSave
formatter
fromhex
Expand Down