Skip to content
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

feat(fw,tests): EIP-7742: Framework changes #931

Merged
merged 13 commits into from
Dec 5, 2024
Merged
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Test fixtures for use by clients are available for each release on the [Github r
- 🔀 Update `pydantic` from 2.8.2 to 2.9.2 ([#960](https://github.com/ethereum/execution-spec-tests/pull/960)).
- ✨ Add the `eest make test` command, an interactive CLI that helps users create a new test module and function ([#950](https://github.com/ethereum/execution-spec-tests/pull/950)).
- ✨ Add the `eest clean` command that helps delete generated files and directories from the repository ([#980](https://github.com/ethereum/execution-spec-tests/pull/980)).
- ✨ Add framework changes for EIP-7742, required for Prague devnet-5 ([#931](https://github.com/ethereum/execution-spec-tests/pull/931)).

### 🔧 EVM Tools

Expand Down
87 changes: 58 additions & 29 deletions src/ethereum_test_fixtures/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@
"""

from functools import cached_property
from typing import Annotated, Any, ClassVar, List, Literal, Tuple, Union, get_args, get_type_hints
from typing import (
Annotated,
Any,
ClassVar,
List,
Literal,
Tuple,
Union,
cast,
get_args,
get_type_hints,
)

from ethereum import rlp as eth_rlp
from ethereum_types.numeric import Uint
Expand Down Expand Up @@ -97,9 +108,13 @@ class FixtureHeader(CamelModel):
extra_data: Bytes
prev_randao: Hash = Field(Hash(0), alias="mixHash")
nonce: HeaderNonce = Field(HeaderNonce(0), validate_default=True)
base_fee_per_gas: Annotated[
ZeroPaddedHexNumber, HeaderForkRequirement("base_fee")
] | None = Field(None)
base_fee_per_gas: (
Annotated[
ZeroPaddedHexNumber,
HeaderForkRequirement("base_fee"),
]
| None
) = Field(None)
withdrawals_root: Annotated[Hash, HeaderForkRequirement("withdrawals")] | None = Field(None)
blob_gas_used: (
Annotated[ZeroPaddedHexNumber, HeaderForkRequirement("blob_gas_used")] | None
Expand All @@ -111,6 +126,9 @@ class FixtureHeader(CamelModel):
None
)
requests_hash: Annotated[Hash, HeaderForkRequirement("requests")] | None = Field(None)
target_blobs_per_block: (
Annotated[ZeroPaddedHexNumber, HeaderForkRequirement("target_blobs_per_block")] | None
) = Field(None)

fork: Fork | None = Field(None, exclude=True)

Expand Down Expand Up @@ -224,7 +242,13 @@ def from_fixture_header(

EngineNewPayloadV1Parameters = Tuple[FixtureExecutionPayload]
EngineNewPayloadV3Parameters = Tuple[FixtureExecutionPayload, List[Hash], Hash]
EngineNewPayloadV4Parameters = Tuple[FixtureExecutionPayload, List[Hash], Hash, List[Bytes]]
EngineNewPayloadV4Parameters = Tuple[
FixtureExecutionPayload,
List[Hash],
Hash,
List[Bytes],
HexNumber,
]

# Important: We check EngineNewPayloadV3Parameters first as it has more fields, and pydantic
# has a weird behavior when the smaller tuple is checked first.
Expand Down Expand Up @@ -286,32 +310,37 @@ def from_fixture_header(
transactions=transactions,
withdrawals=withdrawals,
)
params: EngineNewPayloadParameters
if (
fork.engine_new_payload_requests(header.number, header.timestamp)
and requests is not None
):
parent_beacon_block_root = header.parent_beacon_block_root
assert parent_beacon_block_root is not None
params = (
execution_payload,
Transaction.list_blob_versioned_hashes(transactions),
parent_beacon_block_root,
requests,
)
elif fork.engine_new_payload_blob_hashes(header.number, header.timestamp):
parent_beacon_block_root = header.parent_beacon_block_root
assert parent_beacon_block_root is not None
params = (
execution_payload,
Transaction.list_blob_versioned_hashes(transactions),
parent_beacon_block_root,
)
else:
params = (execution_payload,)

params: List[Any] = [execution_payload]
if fork.engine_new_payload_blob_hashes(header.number, header.timestamp):
blob_hashes = Transaction.list_blob_versioned_hashes(transactions)
if blob_hashes is None:
raise ValueError(f"Blob hashes are required for ${fork}.")
params.append(blob_hashes)

if fork.engine_new_payload_beacon_root(header.number, header.timestamp):
parent_beacon_block_root = header.parent_beacon_block_root
if parent_beacon_block_root is None:
raise ValueError(f"Parent beacon block root is required for ${fork}.")
params.append(parent_beacon_block_root)

if fork.engine_new_payload_requests(header.number, header.timestamp):
if requests is None:
raise ValueError(f"Requests are required for ${fork}.")
params.append(requests)

if fork.engine_new_payload_target_blobs_per_block(header.number, header.timestamp):
target_blobs_per_block = header.target_blobs_per_block
if target_blobs_per_block is None:
raise ValueError(f"Target blobs per block is required for ${fork}.")
params.append(target_blobs_per_block)

payload_params: EngineNewPayloadParameters = cast(
EngineNewPayloadParameters,
tuple(params),
)
new_payload = cls(
params=params,
params=payload_params,
new_payload_version=new_payload_version,
forkchoice_updated_version=forkchoice_updated_version,
**kwargs,
Expand Down
17 changes: 12 additions & 5 deletions src/ethereum_test_fixtures/tests/test_blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
Bytes,
Hash,
HeaderNonce,
HexNumber,
TestPrivateKey,
ZeroPaddedHexNumber,
to_json,
Expand Down Expand Up @@ -668,6 +669,7 @@
excess_blob_gas=18,
parent_beacon_block_root=19,
requests_hash=20,
target_blobs_per_block=21,
),
transactions=[
Transaction(
Expand Down Expand Up @@ -729,7 +731,7 @@
"blobGasUsed": hex(17),
"excessBlobGas": hex(18),
"blockHash": (
"0x93bd662d8a80a1f54bffc6d140b83d6cda233209998809f9540be51178b4d0b6"
"0x9f6459fb2eca2b75ee861e97d679ba91457bb446c8484a7ad76d1675a7f78fde"
),
"transactions": [
Transaction(
Expand Down Expand Up @@ -787,8 +789,9 @@
),
).requests_list
],
HexNumber(21).hex(),
],
"forkchoiceUpdatedVersion": "3",
"forkchoiceUpdatedVersion": "4",
"newPayloadVersion": "4",
"validationError": "BlockException.INCORRECT_BLOCK_FORMAT"
"|TransactionException.INTRINSIC_GAS_TOO_LOW",
Expand Down Expand Up @@ -823,6 +826,7 @@
excess_blob_gas=18,
parent_beacon_block_root=19,
requests_hash=20,
target_blobs_per_block=21,
),
transactions=[
Transaction(
Expand Down Expand Up @@ -883,7 +887,7 @@
"blobGasUsed": hex(17),
"excessBlobGas": hex(18),
"blockHash": (
"0x93bd662d8a80a1f54bffc6d140b83d6cda233209998809f9540be51178b4d0b6"
"0x9f6459fb2eca2b75ee861e97d679ba91457bb446c8484a7ad76d1675a7f78fde"
),
"transactions": [
Transaction(
Expand Down Expand Up @@ -941,9 +945,10 @@
),
).requests_list
],
HexNumber(21).hex(),
],
"newPayloadVersion": "4",
"forkchoiceUpdatedVersion": "3",
"forkchoiceUpdatedVersion": "4",
"validationError": "BlockException.INCORRECT_BLOCK_FORMAT"
"|TransactionException.INTRINSIC_GAS_TOO_LOW",
},
Expand Down Expand Up @@ -1163,7 +1168,7 @@ def test_json_deserialization(
id="fixture_engine_new_payload_parameters_v3",
),
pytest.param(
False,
True,
EngineNewPayloadParametersAdapter,
(
FixtureExecutionPayload.from_fixture_header(
Expand Down Expand Up @@ -1227,6 +1232,7 @@ def test_json_deserialization(
target_pubkey=BLSPublicKey(2),
),
).requests_list,
HexNumber(9),
),
[
{
Expand Down Expand Up @@ -1292,6 +1298,7 @@ def test_json_deserialization(
),
).requests_list
],
HexNumber(9).hex(),
],
id="fixture_engine_new_payload_parameters_v4",
),
Expand Down
55 changes: 55 additions & 0 deletions src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,14 @@ def transaction_intrinsic_cost_calculator(
"""
pass

@classmethod
@abstractmethod
def header_target_blobs_per_block_required(cls, block_number: int, timestamp: int) -> bool:
"""
Returns true if the header must contain target blobs per block.
"""
pass

@classmethod
@abstractmethod
def blob_gas_per_blob(cls, block_number: int, timestamp: int) -> int:
Expand All @@ -254,6 +262,22 @@ def blob_gas_per_blob(cls, block_number: int, timestamp: int) -> int:
"""
pass

@classmethod
@abstractmethod
def target_blobs_per_block(cls, block_number: int, timestamp: int) -> int:
"""
Returns the target blobs per block for a given fork.
"""
pass

@classmethod
@abstractmethod
def max_blobs_per_block(cls, block_number: int, timestamp: int) -> int:
"""
Returns the max blobs per block for a given fork.
"""
pass

@classmethod
@abstractmethod
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
Expand Down Expand Up @@ -357,6 +381,37 @@ def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0)
"""
pass

@classmethod
@abstractmethod
def engine_new_payload_target_blobs_per_block(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if the engine api version requires new payload calls to include
target blobs per block.
"""
pass

@classmethod
@abstractmethod
def engine_payload_attribute_target_blobs_per_block(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if the payload attributes include the target blobs per block.
"""
pass

@classmethod
@abstractmethod
def engine_payload_attribute_max_blobs_per_block(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if the payload attributes include the max blobs per block.
"""
pass

@classmethod
@abstractmethod
def engine_forkchoice_updated_version(
Expand Down
Loading
Loading