diff --git a/src/ethereum_test_forks/base_fork.py b/src/ethereum_test_forks/base_fork.py index 2ddfbe13c2f..da2408dd3bb 100644 --- a/src/ethereum_test_forks/base_fork.py +++ b/src/ethereum_test_forks/base_fork.py @@ -1,6 +1,7 @@ """ Abstract base class for Ethereum forks """ + from abc import ABC, ABCMeta, abstractmethod from typing import Any, List, Mapping, Optional, Protocol, Type @@ -55,7 +56,7 @@ def fork(cls, block_number: int = 0, timestamp: int = 0) -> str: # Header information abstract methods @classmethod @abstractmethod - def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: + def header_base_fee_per_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: """ Returns true if the header must contain base fee """ diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index c13b41438a3..06c807b1345 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -1,6 +1,7 @@ """ All Ethereum fork class definitions. """ + from typing import List, Mapping, Optional from ..base_fork import BaseFork @@ -20,7 +21,7 @@ def fork(cls, block_number: int = 0, timestamp: int = 0) -> str: return cls.name() @classmethod - def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: + def header_base_fee_per_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: """ At genesis, header must not contain base fee """ @@ -231,7 +232,7 @@ class London(Berlin): """ @classmethod - def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: + def header_base_fee_per_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: """ Base Fee is required starting from London. """ diff --git a/src/ethereum_test_forks/tests/test_forks.py b/src/ethereum_test_forks/tests/test_forks.py index 61cddd1ea17..8e3d6694763 100644 --- a/src/ethereum_test_forks/tests/test_forks.py +++ b/src/ethereum_test_forks/tests/test_forks.py @@ -46,8 +46,8 @@ def test_transition_forks(): assert MergeToShanghaiAtTime15k.fork(0, 15_000) == "Shanghai" assert MergeToShanghaiAtTime15k.fork() == "Shanghai" - assert BerlinToLondonAt5.header_base_fee_required(4, 0) is False - assert BerlinToLondonAt5.header_base_fee_required(5, 0) is True + assert BerlinToLondonAt5.header_base_fee_per_gas_required(4, 0) is False + assert BerlinToLondonAt5.header_base_fee_per_gas_required(5, 0) is True assert MergeToShanghaiAtTime15k.header_withdrawals_required(0, 14_999) is False assert MergeToShanghaiAtTime15k.header_withdrawals_required(0, 15_000) is True @@ -81,15 +81,15 @@ def test_forks(): assert f"{MergeToShanghaiAtTime15k}" == "MergeToShanghaiAtTime15k" # Test some fork properties - assert Berlin.header_base_fee_required(0, 0) is False - assert London.header_base_fee_required(0, 0) is True - assert Merge.header_base_fee_required(0, 0) is True + assert Berlin.header_base_fee_per_gas_required(0, 0) is False + assert London.header_base_fee_per_gas_required(0, 0) is True + assert Merge.header_base_fee_per_gas_required(0, 0) is True # Default values of normal forks if the genesis block - assert Merge.header_base_fee_required() is True + assert Merge.header_base_fee_per_gas_required() is True # Transition forks too - assert cast(Fork, BerlinToLondonAt5).header_base_fee_required(4, 0) is False - assert cast(Fork, BerlinToLondonAt5).header_base_fee_required(5, 0) is True + assert cast(Fork, BerlinToLondonAt5).header_base_fee_per_gas_required(4, 0) is False + assert cast(Fork, BerlinToLondonAt5).header_base_fee_per_gas_required(5, 0) is True assert cast(Fork, MergeToShanghaiAtTime15k).header_withdrawals_required(0, 14_999) is False assert cast(Fork, MergeToShanghaiAtTime15k).header_withdrawals_required(0, 15_000) is True assert cast(Fork, MergeToShanghaiAtTime15k).header_withdrawals_required() is True diff --git a/src/ethereum_test_tools/common/types.py b/src/ethereum_test_tools/common/types.py index 2a5fb4e53eb..f4a84f453d2 100644 --- a/src/ethereum_test_tools/common/types.py +++ b/src/ethereum_test_tools/common/types.py @@ -1,6 +1,7 @@ """ Useful types for generating Ethereum tests. """ + from copy import copy, deepcopy from dataclasses import dataclass, fields, replace from itertools import count @@ -874,7 +875,7 @@ def from_withdrawal(cls, w: Withdrawal) -> "FixtureWithdrawal": return cls(**kwargs) -DEFAULT_BASE_FEE = 7 +DEFAULT_BASE_FEE_PER_GAS = 7 @dataclass(kw_only=True) @@ -949,7 +950,7 @@ class Environment: to_json=True, ), ) - base_fee: Optional[NumberConvertible] = field( + base_fee_per_gas: Optional[NumberConvertible] = field( default=None, json_encoder=JSONEncoder.Field( name="currentBaseFee", @@ -970,7 +971,7 @@ class Environment: cast_type=Number, ), ) - parent_base_fee: Optional[NumberConvertible] = field( + parent_base_fee_per_gas: Optional[NumberConvertible] = field( default=None, json_encoder=JSONEncoder.Field( name="parentBaseFee", @@ -1048,13 +1049,15 @@ def from_parent_header(parent: "FixtureHeader") -> "Environment": return Environment( parent_difficulty=parent.difficulty, parent_timestamp=parent.timestamp, - parent_base_fee=parent.base_fee, + parent_base_fee_per_gas=parent.base_fee_per_gas, parent_blob_gas_used=parent.blob_gas_used, parent_excess_blob_gas=parent.excess_blob_gas, parent_gas_used=parent.gas_used, parent_gas_limit=parent.gas_limit, parent_ommers_hash=parent.ommers_hash, - block_hashes={parent.number: parent.hash if parent.hash is not None else 0}, + block_hashes={ + parent.number: parent.block_hash if parent.block_hash is not None else 0 + }, ) def parent_hash(self) -> bytes: @@ -1075,13 +1078,15 @@ def apply_new_parent(self, new_parent: "FixtureHeader") -> "Environment": env = copy(self) env.parent_difficulty = new_parent.difficulty env.parent_timestamp = new_parent.timestamp - env.parent_base_fee = new_parent.base_fee + env.parent_base_fee_per_gas = new_parent.base_fee_per_gas env.parent_blob_gas_used = new_parent.blob_gas_used env.parent_excess_blob_gas = new_parent.excess_blob_gas env.parent_gas_used = new_parent.gas_used env.parent_gas_limit = new_parent.gas_limit env.parent_ommers_hash = new_parent.ommers_hash - env.block_hashes[new_parent.number] = new_parent.hash if new_parent.hash is not None else 0 + env.block_hashes[new_parent.number] = ( + new_parent.block_hash if new_parent.block_hash is not None else 0 + ) return env def set_fork_requirements(self, fork: Fork, in_place: bool = False) -> "Environment": @@ -1098,11 +1103,11 @@ def set_fork_requirements(self, fork: Fork, in_place: bool = False) -> "Environm res.withdrawals = [] if ( - fork.header_base_fee_required(number, timestamp) - and res.base_fee is None - and res.parent_base_fee is None + fork.header_base_fee_per_gas_required(number, timestamp) + and res.base_fee_per_gas is None + and res.parent_base_fee_per_gas is None ): - res.base_fee = DEFAULT_BASE_FEE + res.base_fee_per_gas = DEFAULT_BASE_FEE_PER_GAS if fork.header_zero_difficulty_required(number, timestamp): res.difficulty = 0 @@ -1919,22 +1924,22 @@ class Header: coinbase: Optional[FixedSizeBytesConvertible] = None state_root: Optional[FixedSizeBytesConvertible] = None transactions_root: Optional[FixedSizeBytesConvertible] = None - receipt_root: Optional[FixedSizeBytesConvertible] = None - bloom: Optional[FixedSizeBytesConvertible] = None + receipts_root: Optional[FixedSizeBytesConvertible] = None + logs_bloom: Optional[FixedSizeBytesConvertible] = None difficulty: Optional[NumberConvertible] = None number: Optional[NumberConvertible] = None gas_limit: Optional[NumberConvertible] = None gas_used: Optional[NumberConvertible] = None timestamp: Optional[NumberConvertible] = None extra_data: Optional[BytesConvertible] = None - mix_digest: Optional[FixedSizeBytesConvertible] = None + prev_randao: Optional[FixedSizeBytesConvertible] = None nonce: Optional[FixedSizeBytesConvertible] = None - base_fee: Optional[NumberConvertible | Removable] = None + base_fee_per_gas: Optional[NumberConvertible | Removable] = None withdrawals_root: Optional[FixedSizeBytesConvertible | Removable] = None blob_gas_used: Optional[NumberConvertible | Removable] = None excess_blob_gas: Optional[NumberConvertible | Removable] = None beacon_root: Optional[FixedSizeBytesConvertible | Removable] = None - hash: Optional[FixedSizeBytesConvertible] = None + block_hash: Optional[FixedSizeBytesConvertible] = None REMOVE_FIELD: ClassVar[Removable] = Removable() """ @@ -2085,14 +2090,14 @@ class FixtureHeader: ), json_encoder=JSONEncoder.Field(name="transactionsTrie"), ) - receipt_root: Hash = header_field( + receipts_root: Hash = header_field( source=HeaderFieldSource( parse_type=Hash, source_transition_tool="receiptsRoot", ), json_encoder=JSONEncoder.Field(name="receiptTrie"), ) - bloom: Bloom = header_field( + logs_bloom: Bloom = header_field( source=HeaderFieldSource( parse_type=Bloom, source_transition_tool="logsBloom", @@ -2144,7 +2149,7 @@ class FixtureHeader: ), json_encoder=JSONEncoder.Field(name="extraData"), ) - mix_digest: Hash = header_field( + prev_randao: Hash = header_field( source=HeaderFieldSource( parse_type=Hash, source_environment="prev_randao", @@ -2159,13 +2164,13 @@ class FixtureHeader: ), json_encoder=JSONEncoder.Field(), ) - base_fee: Optional[int] = header_field( + base_fee_per_gas: Optional[int] = header_field( default=None, source=HeaderFieldSource( parse_type=Number, - fork_requirement_check="header_base_fee_required", + fork_requirement_check="header_base_fee_per_gas_required", source_transition_tool="currentBaseFee", - source_environment="base_fee", + source_environment="base_fee_per_gas", ), json_encoder=JSONEncoder.Field(name="baseFeePerGas", cast_type=ZeroPaddedHexNumber), ) @@ -2205,7 +2210,7 @@ class FixtureHeader: ), json_encoder=JSONEncoder.Field(name="parentBeaconBlockRoot"), ) - hash: Optional[Hash] = header_field( + block_hash: Optional[Hash] = header_field( default=None, source=HeaderFieldSource( required=False, @@ -2314,19 +2319,19 @@ def build( self.coinbase, self.state_root, self.transactions_root, - self.receipt_root, - self.bloom, + self.receipts_root, + self.logs_bloom, Uint(int(self.difficulty)), Uint(int(self.number)), Uint(int(self.gas_limit)), Uint(int(self.gas_used)), Uint(int(self.timestamp)), self.extra_data, - self.mix_digest, + self.prev_randao, self.nonce, ] - if self.base_fee is not None: - header.append(Uint(int(self.base_fee))) + if self.base_fee_per_gas is not None: + header.append(Uint(int(self.base_fee_per_gas))) if self.withdrawals_root is not None: header.append(self.withdrawals_root) if self.blob_gas_used is not None: @@ -2413,8 +2418,8 @@ def set_environment(self, env: Environment) -> Environment: new_env.gas_limit = ( self.gas_limit if self.gas_limit is not None else environment_default.gas_limit ) - if not isinstance(self.base_fee, Removable): - new_env.base_fee = self.base_fee + if not isinstance(self.base_fee_per_gas, Removable): + new_env.base_fee_per_gas = self.base_fee_per_gas new_env.withdrawals = self.withdrawals if not isinstance(self.excess_blob_gas, Removable): new_env.excess_blob_gas = self.excess_blob_gas @@ -2486,34 +2491,6 @@ class FixtureExecutionPayload(FixtureHeader): ), ) - # Fields with different names - coinbase: Address = field( - json_encoder=JSONEncoder.Field( - name="feeRecipient", - ) - ) - receipt_root: Hash = field( - json_encoder=JSONEncoder.Field( - name="receiptsRoot", - ), - ) - bloom: Bloom = field( - json_encoder=JSONEncoder.Field( - name="logsBloom", - ) - ) - mix_digest: Hash = field( - json_encoder=JSONEncoder.Field( - name="prevRandao", - ), - ) - hash: Optional[Hash] = field( - default=None, - json_encoder=JSONEncoder.Field( - name="blockHash", - ), - ) - # Fields with different formatting number: int = field( json_encoder=JSONEncoder.Field( @@ -2524,7 +2501,7 @@ class FixtureExecutionPayload(FixtureHeader): gas_limit: int = field(json_encoder=JSONEncoder.Field(name="gasLimit", cast_type=HexNumber)) gas_used: int = field(json_encoder=JSONEncoder.Field(name="gasUsed", cast_type=HexNumber)) timestamp: int = field(json_encoder=JSONEncoder.Field(cast_type=HexNumber)) - base_fee: Optional[int] = field( + base_fee_per_gas: Optional[int] = field( default=None, json_encoder=JSONEncoder.Field(name="baseFeePerGas", cast_type=HexNumber), ) @@ -2694,7 +2671,7 @@ def _withdrawals_encoder(withdrawals: List[Withdrawal]) -> List[FixtureWithdrawa cast_type=Number, ), ) - txs: Optional[List[Transaction]] = field( + transactions: Optional[List[Transaction]] = field( default=None, json_encoder=JSONEncoder.Field( name="transactions", diff --git a/src/ethereum_test_tools/consume/__init__.py b/src/ethereum_test_tools/consume/__init__.py new file mode 100644 index 00000000000..55f31775df0 --- /dev/null +++ b/src/ethereum_test_tools/consume/__init__.py @@ -0,0 +1,12 @@ +""" +Consume methods and types used for EEST based test runners (consumers). +""" + +from .engine_rpc import EngineRPC +from .eth_rpc import BlockNumberType, EthRPC + +__all__ = ( + "BlockNumberType", + "EthRPC", + "EngineRPC", +) diff --git a/src/ethereum_test_tools/consume/base_rpc.py b/src/ethereum_test_tools/consume/base_rpc.py new file mode 100644 index 00000000000..0f184ce3c3d --- /dev/null +++ b/src/ethereum_test_tools/consume/base_rpc.py @@ -0,0 +1,48 @@ +""" +Base JSON-RPC class and helper functions for EEST based hive simulators. +""" + +import time + +import jwt +import requests + +# from jwt import encode + + +class BaseRPC: + """ + Represents a base RPC class for every RPC call used within EEST based hive simulators. + """ + + def __init__(self, client): + self.client = client + self.url = f"http://{client.ip}:8551" + self.jwt_secret = ( + b"secretsecretsecretsecretsecretse" # oh wow, guess its not a secret anymore + ) + + def generate_jwt_token(self): + """ + Generates a JWT token based on the issued at timestamp and JWT secret. + """ + iat = int(time.time()) + return jwt.encode({"iat": iat}, self.jwt_secret, algorithm="HS256") + + def post_request(self, method, params): + """ + Sends a JSON-RPC POST request to the client RPC server at port 8551. + """ + payload = { + "jsonrpc": "2.0", + "method": method, + "params": params, + "id": 1, + } + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {self.generate_jwt_token()}", + } + response = requests.post(self.url, json=payload, headers=headers) + response.raise_for_status() + return response.json().get("result") diff --git a/src/ethereum_test_tools/consume/engine_rpc.py b/src/ethereum_test_tools/consume/engine_rpc.py new file mode 100644 index 00000000000..a361f0f6531 --- /dev/null +++ b/src/ethereum_test_tools/consume/engine_rpc.py @@ -0,0 +1,49 @@ +""" +Ethereum `engine_X` JSON-RPC Engine API methods used within EEST based hive simulators. +""" + +from typing import Dict + +from ..common.json import to_json +from ..common.types import FixtureEngineNewPayload +from .base_rpc import BaseRPC + +ForkchoiceStateV1 = Dict +PayloadAttributes = Dict + + +class EngineRPC(BaseRPC): + """ + Represents an Engine API RPC class for every Engine API method used within EEST based hive + simulators. + """ + + def new_payload( + self, + engine_new_payload: FixtureEngineNewPayload, + ): + """ + `engine_newPayloadVX`: Attempts to execute the given payload on an execution client. + """ + version = engine_new_payload.version + engine_new_payload_json = to_json(engine_new_payload) + formatted_json = [ + engine_new_payload_json.get("executionPayload", None), + ] + if version >= 3: + formatted_json.append(engine_new_payload_json.get("expectedBlobVersionedHashes", None)) + formatted_json.append(engine_new_payload_json.get("parentBeaconBlockRoot", None)) + + return self.post_request(f"engine_newPayloadV{version}", formatted_json) + + def forkchoice_updated( + self, + forkchoice_state: ForkchoiceStateV1, + payload_attributes: PayloadAttributes, + version: int = 1, + ): + """ + `engine_forkchoiceUpdatedVX`: Updates the forkchoice state of the execution client. + """ + payload_params = [forkchoice_state, payload_attributes] + return self.post_request(f"engine_forkchoiceUpdatedV{version}", payload_params) diff --git a/src/ethereum_test_tools/consume/eth_rpc.py b/src/ethereum_test_tools/consume/eth_rpc.py new file mode 100644 index 00000000000..f9881079300 --- /dev/null +++ b/src/ethereum_test_tools/consume/eth_rpc.py @@ -0,0 +1,62 @@ +""" +Ethereum `eth_X` JSON-RPC methods used within EEST based hive simulators. +""" + +from typing import Dict, List, Literal, Union + +from ..common import Address +from .base_rpc import BaseRPC + +BlockNumberType = Union[int, Literal["latest", "earliest", "pending"]] + + +class EthRPC(BaseRPC): + """ + Represents an `eth_X` RPC class for every default ethereum RPC method used within EEST based + hive simulators. + """ + + def get_block_by_number(self, block_number: BlockNumberType = "latest", full_txs: bool = True): + """ + `eth_getBlockByNumber`: Returns information about a block by block number. + """ + block = hex(block_number) if isinstance(block_number, int) else block_number + return self.post_request("eth_getBlockByNumber", [block, full_txs]) + + def get_balance(self, address: str, block_number: BlockNumberType = "latest"): + """ + `eth_getBalance`: Returns the balance of the account of given address. + """ + block = hex(block_number) if isinstance(block_number, int) else block_number + return self.post_request("eth_getBalance", [address, block]) + + def get_transaction_count(self, address: Address, block_number: BlockNumberType = "latest"): + """ + `eth_getTransactionCount`: Returns the number of transactions sent from an address. + """ + block = hex(block_number) if isinstance(block_number, int) else block_number + return self.post_request("eth_getTransactionCount", [address, block]) + + def get_storage_at( + self, address: str, position: str, block_number: BlockNumberType = "latest" + ): + """ + `eth_getStorageAt`: Returns the value from a storage position at a given address. + """ + block = hex(block_number) if isinstance(block_number, int) else block_number + return self.post_request("eth_getStorageAt", [address, position, block]) + + def storage_at_keys( + self, account: str, keys: List[str], block_number: BlockNumberType = "latest" + ) -> Dict: + """ + Helper to retrieve the storage values for the specified keys at a given address and block + number. + """ + if isinstance(block_number, int): + block_number + results: Dict = {} + for key in keys: + storage_value = self.get_storage_at(account, key, block_number) + results[key] = storage_value + return results diff --git a/src/ethereum_test_tools/consume/types.py b/src/ethereum_test_tools/consume/types.py new file mode 100644 index 00000000000..5193348a55e --- /dev/null +++ b/src/ethereum_test_tools/consume/types.py @@ -0,0 +1,425 @@ +""" +Useful types for consuming EEST test runners or hive simulators. +""" + +from dataclasses import dataclass, fields +from typing import List, Union + +from ..common.conversions import BytesConvertible +from ..common.json import JSONEncoder, field, to_json +from ..common.types import ( + Address, + Bloom, + Bytes, + FixtureBlock, + Hash, + HexNumber, + blob_versioned_hashes_from_transactions, +) + + +class EngineParis: + """ + Paris (Merge) Engine API structures: + https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md + """ + + @dataclass(kw_only=True) + class ExecutionPayloadV1: + """ + Structure of a version 1 execution payload: + https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#executionpayloadv1 + """ + + parent_hash: Hash = field( + json_encoder=JSONEncoder.Field( + name="parentHash", + ), + ) + """ + parentHash: DATA, 32 Bytes + """ + coinbase: Address = field( + json_encoder=JSONEncoder.Field( + name="feeRecipient", + ), + ) + """ + feeRecipient: DATA, 20 Bytes + """ + state_root: Hash = field( + json_encoder=JSONEncoder.Field( + name="stateRoot", + ), + ) + """ + stateRoot: DATA, 32 Bytes + """ + receipts_root: Hash = field( + json_encoder=JSONEncoder.Field( + name="receiptsRoot", + ), + ) + """ + receiptsRoot: DATA, 32 Bytes + """ + logs_bloom: Bloom = field( + json_encoder=JSONEncoder.Field( + name="logsBloom", + ), + ) + """ + logsBloom: DATA, 256 Bytes + """ + prev_randao: Hash = field( + json_encoder=JSONEncoder.Field( + name="prevRandao", + ), + ) + """ + prevRandao: DATA, 32 Bytes + """ + number: int = field( + json_encoder=JSONEncoder.Field( + name="blockNumber", + cast_type=HexNumber, + ), + ) + """ + blockNumber: QUANTITY, 64 Bits + """ + gas_limit: int = field( + json_encoder=JSONEncoder.Field( + name="gasLimit", + cast_type=HexNumber, + ), + ) + """ + gasLimit: QUANTITY, 64 Bits + """ + gas_used: int = field( + json_encoder=JSONEncoder.Field( + name="gasUsed", + cast_type=HexNumber, + ), + ) + """ + gasUsed: QUANTITY, 64 Bits + """ + timestamp: int = field( + json_encoder=JSONEncoder.Field( + name="timestamp", + cast_type=HexNumber, + ), + ) + """ + timestamp: QUANTITY, 64 Bits + """ + extra_data: Bytes = field( + json_encoder=JSONEncoder.Field( + name="extraData", + ), + ) + """ + extraData: DATA, 0 to 32 Bytes + """ + base_fee_per_gas: int = field( + json_encoder=JSONEncoder.Field( + name="baseFeePerGas", + cast_type=HexNumber, + ), + ) + """ + baseFeePerGas: QUANTITY, 64 Bits + """ + block_hash: Hash = field( + json_encoder=JSONEncoder.Field( + name="blockHash", + ), + ) + """ + blockHash: DATA, 32 Bytes + """ + transactions: List[BytesConvertible] = field( + json_encoder=JSONEncoder.Field( + name="transactions", + to_json=True, + ), + ) + """ + transactions: Array of DATA + """ + + @classmethod + def from_fixture_block( + cls, fixture_block: FixtureBlock + ) -> "EngineParis.ExecutionPayloadV1": + """ + Converts a fixture block to a Paris execution payload. + """ + header = fixture_block.block_header + transactions = [ + "0x" + tx.serialized_bytes().hex() for tx in fixture_block.transactions + ] + + kwargs = { + field.name: getattr(header, field.name) + for field in fields(header) + if field.name in {f.name for f in fields(cls)} + } + + return cls(**kwargs, transactions=transactions) + + @dataclass(kw_only=True) + class NewPayloadV1: + """ + Structure of a version 1 engine new payload: + https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#engine_newpayloadv1 + """ + + execution_payload: "EngineParis.ExecutionPayloadV1" = field( + json_encoder=JSONEncoder.Field( + name="executionPayload", + to_json=True, + ), + ) + + @classmethod + def from_fixture_block(cls, fixture_block: FixtureBlock) -> "EngineParis.NewPayloadV1": + """ + Creates a Paris engine new payload from a fixture block. + """ + return EngineParis.NewPayloadV1( + execution_payload=EngineParis.ExecutionPayloadV1.from_fixture_block(fixture_block) + ) + + def to_json_rpc(self) -> dict: + """ + Serializes a Paris engine new payload dataclass to its JSON-RPC representation. + """ + return [to_json(self.execution_payload)] + + +class EngineShanghai: + """ + Shanghai Engine API structures: + https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md + """ + + @dataclass(kw_only=True) + class WithdrawalV1: + """ + Structure of a version 1 withdrawal: + https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#withdrawalv1 + """ + + index: int = field( + json_encoder=JSONEncoder.Field( + name="index", + cast_type=HexNumber, + ), + ) + """ + index: QUANTITY, 64 Bits + """ + validator_index: int = field( + json_encoder=JSONEncoder.Field( + name="validatorIndex", + cast_type=HexNumber, + ), + ) + """ + validatorIndex: QUANTITY, 64 Bits + """ + address: Address = field( + json_encoder=JSONEncoder.Field( + name="address", + ), + ) + """ + address: DATA, 20 Bytes + """ + amount: int = field( + json_encoder=JSONEncoder.Field( + name="amount", + cast_type=HexNumber, + ), + ) + """ + amount: QUANTITY, 64 Bits + """ + + @dataclass(kw_only=True) + class ExecutionPayloadV2(EngineParis.ExecutionPayloadV1): + """ + Structure of a version 2 execution payload: + https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#executionpayloadv2 + """ + + withdrawals: List["EngineShanghai.WithdrawalV1"] = field( + json_encoder=JSONEncoder.Field( + name="withdrawals", + to_json=True, + ), + ) + """ + withdrawals: Array of WithdrawalV1 + """ + + @classmethod + def from_fixture_block( + cls, fixture_block: FixtureBlock + ) -> "EngineShanghai.ExecutionPayloadV2": + """ + Converts a fixture block to a Shanghai execution payload. + """ + header = fixture_block.block_header + transactions = [ + "0x" + tx.serialized_bytes().hex() for tx in fixture_block.transactions + ] + withdrawals = fixture_block.withdrawals + + kwargs = { + field.name: getattr(header, field.name) + for field in fields(header) + if field.name in {f.name for f in fields(cls)} + } + + return cls(**kwargs, transactions=transactions, withdrawals=withdrawals) + + @dataclass(kw_only=True) + class NewPayloadV2: + """ + Structure of a version 2 engine new payload: + https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#engine_newpayloadv2 + """ + + execution_payload: Union[ + "EngineShanghai.ExecutionPayloadV2", EngineParis.ExecutionPayloadV1 + ] = field( + json_encoder=JSONEncoder.Field( + name="executionPayload", + to_json=True, + ), + ) + + @classmethod + def from_fixture_block(cls, fixture_block: FixtureBlock) -> "EngineShanghai.NewPayloadV2": + """ + Creates a Shanghai engine new payload from a fixture block. + """ + return EngineShanghai.NewPayloadV2( + execution_payload=EngineShanghai.ExecutionPayloadV2.from_fixture_block( + fixture_block + ) + ) + + def to_json_rpc(self) -> dict: + """ + Serializes a Shanghai engine new payload dataclass to its JSON-RPC representation. + """ + return [to_json(self.execution_payload)] + + +class EngineCancun: + """ + Cancun Engine API structures: + https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md + """ + + @dataclass(kw_only=True) + class ExecutionPayloadV3(EngineShanghai.ExecutionPayloadV2): + """ + Structure of a version 3 execution payload: + https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#executionpayloadv3 + """ + + blob_gas_used: int = field( + json_encoder=JSONEncoder.Field( + name="blobGasUsed", + cast_type=HexNumber, + ), + ) + """ + blobGasUsed: QUANTITY, 64 Bits + """ + excess_blob_gas: int = field( + json_encoder=JSONEncoder.Field( + name="excessBlobGas", + cast_type=HexNumber, + ), + ) + """ + excessBlobGas: QUANTITY, 64 Bits + """ + + @classmethod + def from_fixture_block( + cls, fixture_block: FixtureBlock + ) -> "EngineCancun.ExecutionPayloadV3": + """ + Converts a fixture block to a Cancun execution payload. + """ + header = fixture_block.block_header + transactions = [ + "0x" + tx.serialized_bytes().hex() for tx in fixture_block.transactions + ] + withdrawals = fixture_block.withdrawals + + kwargs = { + field.name: getattr(header, field.name) + for field in fields(header) + if field.name in {f.name for f in fields(cls)} + } + + return cls(**kwargs, transactions=transactions, withdrawals=withdrawals) + + @dataclass(kw_only=True) + class NewPayloadV3: + """ + Structure of a version 3 engine new payload: + https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3 + """ + + execution_payload: "EngineCancun.ExecutionPayloadV3" = field( + json_encoder=JSONEncoder.Field( + to_json=True, + ), + ) + """ + executionPayload: ExecutionPayloadV3 + """ + expected_blob_versioned_hashes: List[Hash] + """ + expectedBlobVersionedHashes: Array of DATA + """ + parent_beacon_block_root: Hash + """ + parentBeaconBlockRoot: DATA, 32 Bytes + """ + + @classmethod + def from_fixture_block(cls, fixture_block: FixtureBlock) -> "EngineCancun.NewPayloadV3": + """ + Creates a Cancun engine new payload from a fixture block. + """ + execution_payload = EngineCancun.ExecutionPayloadV3.from_fixture_block(fixture_block) + expected_blob_versioned_hashes = blob_versioned_hashes_from_transactions( + fixture_block.transactions + ) + parent_beacon_block_root = fixture_block.block_header.beacon_root + return cls( + execution_payload=execution_payload, + expected_blob_versioned_hashes=expected_blob_versioned_hashes, + parent_beacon_block_root=parent_beacon_block_root, + ) + + def to_json_rpc(self) -> dict: + """ + Serializes a Cancun engine new payload dataclass to its JSON-RPC representation. + """ + return [ + to_json(self.execution_payload), + self.expected_blob_versioned_hashes, + self.parent_beacon_block_root, + ] diff --git a/src/ethereum_test_tools/spec/blockchain_test.py b/src/ethereum_test_tools/spec/blockchain_test.py index 0a4c32a509e..f64b6486143 100644 --- a/src/ethereum_test_tools/spec/blockchain_test.py +++ b/src/ethereum_test_tools/spec/blockchain_test.py @@ -93,17 +93,17 @@ def make_genesis( coinbase=Address(0), state_root=Hash(state_root), transactions_root=Hash(EmptyTrieRoot), - receipt_root=Hash(EmptyTrieRoot), - bloom=Bloom(0), + receipts_root=Hash(EmptyTrieRoot), + logs_bloom=Bloom(0), difficulty=ZeroPaddedHexNumber(0x20000 if env.difficulty is None else env.difficulty), number=0, gas_limit=ZeroPaddedHexNumber(env.gas_limit), gas_used=0, timestamp=0, extra_data=Bytes([0]), - mix_digest=Hash(0), + prev_randao=Hash(0), nonce=HeaderNonce(0), - base_fee=ZeroPaddedHexNumber.or_none(env.base_fee), + base_fee_per_gas=ZeroPaddedHexNumber.or_none(env.base_fee_per_gas), blob_gas_used=ZeroPaddedHexNumber.or_none(env.blob_gas_used), excess_blob_gas=ZeroPaddedHexNumber.or_none(env.excess_blob_gas), withdrawals_root=Hash.or_none( @@ -112,7 +112,7 @@ def make_genesis( beacon_root=Hash.or_none(env.beacon_root), ) - genesis_rlp, genesis.hash = genesis.build( + genesis_rlp, genesis.block_hash = genesis.build( txs=[], ommers=[], withdrawals=env.withdrawals, @@ -191,7 +191,7 @@ def generate_block_data( # transition tool processing. header = header.join(block.rlp_modifier) - rlp, header.hash = header.build( + rlp, header.block_hash = header.build( txs=txs, ommers=[], withdrawals=env.withdrawals, @@ -230,7 +230,7 @@ def make_fixture( alloc = to_json(pre) env = Environment.from_parent_header(genesis) - head = genesis.hash if genesis.hash is not None else Hash(0) + head = genesis.block_hash if genesis.block_hash is not None else Hash(0) for block in self.blocks: header, rlp, txs, new_alloc, new_env = self.generate_block_data( @@ -246,7 +246,7 @@ def make_fixture( rlp=rlp, block_header=header, block_number=Number(header.number), - txs=txs, + transactions=txs, ommers=[], withdrawals=new_env.withdrawals, ), @@ -254,7 +254,7 @@ def make_fixture( # Update env, alloc and last block hash for the next block. alloc = new_alloc env = new_env.apply_new_parent(header) - head = header.hash if header.hash is not None else Hash(0) + head = header.block_hash if header.block_hash is not None else Hash(0) else: fixture_blocks.append( InvalidFixtureBlock( @@ -262,7 +262,7 @@ def make_fixture( expected_exception=block.exception, rlp_decoded=FixtureBlock( block_header=header, - txs=txs, + transactions=txs, ommers=[], withdrawals=new_env.withdrawals, ), diff --git a/src/ethereum_test_tools/spec/state_test.py b/src/ethereum_test_tools/spec/state_test.py index 74321496b4e..facfefb3e7e 100644 --- a/src/ethereum_test_tools/spec/state_test.py +++ b/src/ethereum_test_tools/spec/state_test.py @@ -1,6 +1,7 @@ """ Ethereum state test spec definition and filler. """ + from copy import copy from dataclasses import dataclass from typing import Any, Callable, Dict, Generator, List, Mapping, Optional, Tuple, Type @@ -91,8 +92,8 @@ def make_genesis( coinbase=Address(0), state_root=Hash(state_root), transactions_root=Hash(EmptyTrieRoot), - receipt_root=Hash(EmptyTrieRoot), - bloom=Bloom(0), + receipts_root=Hash(EmptyTrieRoot), + logs_bloom=Bloom(0), difficulty=ZeroPaddedHexNumber( 0x20000 if genesis_env.difficulty is None else genesis_env.difficulty ), @@ -101,9 +102,9 @@ def make_genesis( gas_used=0, timestamp=0, extra_data=Bytes([0]), - mix_digest=Hash(0), + prev_randao=Hash(0), nonce=HeaderNonce(0), - base_fee=ZeroPaddedHexNumber.or_none(genesis_env.base_fee), + base_fee_per_gas=ZeroPaddedHexNumber.or_none(genesis_env.base_fee_per_gas), blob_gas_used=ZeroPaddedHexNumber.or_none(genesis_env.blob_gas_used), excess_blob_gas=ZeroPaddedHexNumber.or_none(genesis_env.excess_blob_gas), withdrawals_root=Hash.or_none( @@ -112,7 +113,7 @@ def make_genesis( beacon_root=Hash.or_none(genesis_env.beacon_root), ) - genesis_rlp, genesis.hash = genesis.build( + genesis_rlp, genesis.block_hash = genesis.build( txs=[], ommers=[], withdrawals=genesis_env.withdrawals, @@ -180,7 +181,11 @@ def make_fixture( header = FixtureHeader.collect( fork=fork, transition_tool_result=t8n_result, environment=self.env ) - block, header.hash = header.build(txs=txs, ommers=[], withdrawals=self.env.withdrawals) + block, header.block_hash = header.build( + txs=txs, + ommers=[], + withdrawals=self.env.withdrawals, + ) return Fixture( fork=network_info, @@ -190,12 +195,12 @@ def make_fixture( FixtureBlock( rlp=block, block_header=header, - txs=txs, + transactions=txs, ommers=[], withdrawals=self.env.withdrawals, ) ], - last_block_hash=header.hash, + last_block_hash=header.block_hash, pre_state=pre, post_state=alloc_to_accounts(t8n_alloc), name=self.tag, @@ -220,7 +225,7 @@ def make_hive_fixture( header = FixtureHeader.collect( fork=fork, transition_tool_result=t8n_result, environment=self.env ) - _, header.hash = header.build(txs=txs, ommers=[], withdrawals=self.env.withdrawals) + _, header.block_hash = header.build(txs=txs, ommers=[], withdrawals=self.env.withdrawals) fixture_payload = FixtureEngineNewPayload.from_fixture_header( fork=fork, header=header, diff --git a/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_cancun_enp.json b/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_cancun_enp.json new file mode 100644 index 00000000000..d64c236c5b3 --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_cancun_enp.json @@ -0,0 +1,25 @@ +[ + { + "parentHash": "0xda9249b7aff004bcdfadfb5f668899746e36a5eee8197d1589deb4a3842251ce", + "feeRecipient": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "stateRoot": "0x3d760432d38fbf795fb9addd6b25a692d82498bd5f7b703a6da6d8647c5b7820", + "receiptsRoot": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "0x1", + "gasLimit": "0x16345785d8a0000", + "gasUsed": "0xa861", + "timestamp": "0xc", + "extraData": "0x", + "baseFeePerGas": "0x7", + "blockHash": "0x546546d8a2d99b3135a47debdfc708e6a2199b8d90e43325d2c0b3adc3613709", + "transactions": [ + "0xf861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b" + ], + "withdrawals": [], + "blobGasUsed": "0x0", + "excessBlobGas": "0x0" + }, + [], + "0x0000000000000000000000000000000000000000000000000000000000000000" +] \ No newline at end of file diff --git a/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_merge_enp.json b/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_merge_enp.json new file mode 100644 index 00000000000..808b234beaa --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_merge_enp.json @@ -0,0 +1,18 @@ +[ + { + "parentHash": "0x86c6dc9cb7b8ada9e27b1cf16fd81f366a0ad8127f42ff13d778eb2ddf7eaa90", + "feeRecipient": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "stateRoot": "0x19919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6", + "receiptsRoot": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "0x1", + "gasLimit": "0x16345785d8a0000", + "gasUsed": "0xa861", + "timestamp": "0xc", + "extraData": "0x", + "baseFeePerGas": "0x7", + "blockHash": "0xe9694e4b99986d312c6891cd7839b73d9e1b451537896818cefeeae97d7e3ea6", + "transactions": ["0xf861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b"] + } +] \ No newline at end of file diff --git a/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_shanghai_enp.json b/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_shanghai_enp.json new file mode 100644 index 00000000000..53c038ff4d8 --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/engine_json/valid_simple_shanghai_enp.json @@ -0,0 +1,19 @@ +[ + { + "parentHash": "0xccb89b5b6043aa73114e6857f0783a02808ea6ff4cabd104a308eb4fe0114a9b", + "feeRecipient": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "stateRoot": "0x19919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6", + "receiptsRoot": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "0x1", + "gasLimit": "0x16345785d8a0000", + "gasUsed": "0xa861", + "timestamp": "0xc", + "extraData": "0x", + "baseFeePerGas": "0x7", + "blockHash": "0xc970b6bcf304cd5c71d24548a7d65dd907a24a3b66229378e2ac42677c1eec2b", + "transactions": ["0xf861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b"], + "withdrawals": [] + } +] \ No newline at end of file diff --git a/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_cancun_blockchain.json b/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_cancun_blockchain.json new file mode 100644 index 00000000000..29969bc7031 --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_cancun_blockchain.json @@ -0,0 +1,131 @@ +{ + "000/valid_blockchain_test/Cancun": { + "_info": { + "filling-transition-tool": "evm version 1.13.12-unstable-253447a4-20240204" + }, + "network": "Cancun", + "genesisRLP": "0xf90240f9023aa00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0789d559bf5d313e15da4139b57627160d23146cf6cdf9995e0394d165b1527efa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000c0c0c0", + "genesisBlockHeader": { + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x789d559bf5d313e15da4139b57627160d23146cf6cdf9995e0394d165b1527ef", + "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x00", + "number": "0x00", + "gasLimit": "0x016345785d8a0000", + "gasUsed": "0x00", + "timestamp": "0x00", + "extraData": "0x00", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x07", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x00", + "excessBlobGas": "0x00", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block_hash": "0xda9249b7aff004bcdfadfb5f668899746e36a5eee8197d1589deb4a3842251ce" + }, + "blocks": [ + { + "rlp": "0xf902a6f9023ca0da9249b7aff004bcdfadfb5f668899746e36a5eee8197d1589deb4a3842251cea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa03d760432d38fbf795fb9addd6b25a692d82498bd5f7b703a6da6d8647c5b7820a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba0c598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0ab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8610c80a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0c0", + "blockHeader": { + "parentHash": "0xda9249b7aff004bcdfadfb5f668899746e36a5eee8197d1589deb4a3842251ce", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "stateRoot": "0x3d760432d38fbf795fb9addd6b25a692d82498bd5f7b703a6da6d8647c5b7820", + "transactionsTrie": "0x8151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcb", + "receiptTrie": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x00", + "number": "0x01", + "gasLimit": "0x016345785d8a0000", + "gasUsed": "0xa861", + "timestamp": "0x0c", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x07", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x00", + "excessBlobGas": "0x00", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block_hash": "0x546546d8a2d99b3135a47debdfc708e6a2199b8d90e43325d2c0b3adc3613709" + }, + "blocknumber": "1", + "transactions": [ + { + "type": "0x00", + "chainId": "0x00", + "nonce": "0x00", + "gasPrice": "0x0a", + "gasLimit": "0x05f5e100", + "to": "0x1000000000000000000000000000000000000000", + "value": "0x00", + "data": "0x", + "v": "0x1b", + "r": "0x7e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37", + "s": "0x5f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + } + ], + "uncleHeaders": [], + "withdrawals": [] + } + ], + "lastblockhash": "0x546546d8a2d99b3135a47debdfc708e6a2199b8d90e43325d2c0b3adc3613709", + "pre": { + "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": { + "nonce": "0x01", + "balance": "0x00", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", + "storage": {} + }, + "0x1000000000000000000000000000000000000000": { + "nonce": "0x00", + "balance": "0x00", + "code": "0x4660015500", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x00", + "balance": "0x3635c9adc5dea00000", + "code": "0x", + "storage": {} + } + }, + "postState": { + "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": { + "nonce": "0x01", + "balance": "0x00", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", + "storage": { + "0x0c": "0x0c" + } + }, + "0x1000000000000000000000000000000000000000": { + "nonce": "0x00", + "balance": "0x00", + "code": "0x4660015500", + "storage": { + "0x01": "0x01" + } + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "nonce": "0x00", + "balance": "0x01f923", + "code": "0x", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x01", + "balance": "0x3635c9adc5de996c36", + "code": "0x", + "storage": {} + } + }, + "sealEngine": "NoProof" + } +} \ No newline at end of file diff --git a/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_merge_blockchain.json b/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_merge_blockchain.json new file mode 100644 index 00000000000..c55796b372d --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_merge_blockchain.json @@ -0,0 +1,108 @@ +{ + "000/valid_blockchain_test/Merge": { + "_info": { + "filling-transition-tool": "evm version 1.13.12-unstable-253447a4-20240204" + }, + "network": "Merge", + "genesisRLP": "0xf901fbf901f6a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0aff9f63320a482f8c4e4f15f659e6a7ac382138fbbb6919243b0cba4c5988a5aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007c0c0", + "genesisBlockHeader": { + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x0000000000000000000000000000000000000000", + "stateRoot": "0xaff9f63320a482f8c4e4f15f659e6a7ac382138fbbb6919243b0cba4c5988a5a", + "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x00", + "number": "0x00", + "gasLimit": "0x016345785d8a0000", + "gasUsed": "0x00", + "timestamp": "0x00", + "extraData": "0x00", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x07", + "block_hash": "0x86c6dc9cb7b8ada9e27b1cf16fd81f366a0ad8127f42ff13d778eb2ddf7eaa90" + }, + "blocks": [ + { + "rlp": "0xf90261f901f8a086c6dc9cb7b8ada9e27b1cf16fd81f366a0ad8127f42ff13d778eb2ddf7eaa90a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa019919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba0c598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0ab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8610c80a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0", + "blockHeader": { + "parentHash": "0x86c6dc9cb7b8ada9e27b1cf16fd81f366a0ad8127f42ff13d778eb2ddf7eaa90", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "stateRoot": "0x19919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6", + "transactionsTrie": "0x8151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcb", + "receiptTrie": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x00", + "number": "0x01", + "gasLimit": "0x016345785d8a0000", + "gasUsed": "0xa861", + "timestamp": "0x0c", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x07", + "block_hash": "0xe9694e4b99986d312c6891cd7839b73d9e1b451537896818cefeeae97d7e3ea6" + }, + "blocknumber": "1", + "transactions": [ + { + "type": "0x00", + "chainId": "0x00", + "nonce": "0x00", + "gasPrice": "0x0a", + "gasLimit": "0x05f5e100", + "to": "0x1000000000000000000000000000000000000000", + "value": "0x00", + "data": "0x", + "v": "0x1b", + "r": "0x7e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37", + "s": "0x5f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + } + ], + "uncleHeaders": [] + } + ], + "lastblockhash": "0xe9694e4b99986d312c6891cd7839b73d9e1b451537896818cefeeae97d7e3ea6", + "pre": { + "0x1000000000000000000000000000000000000000": { + "nonce": "0x00", + "balance": "0x00", + "code": "0x4660015500", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x00", + "balance": "0x3635c9adc5dea00000", + "code": "0x", + "storage": {} + } + }, + "postState": { + "0x1000000000000000000000000000000000000000": { + "nonce": "0x00", + "balance": "0x00", + "code": "0x4660015500", + "storage": { + "0x01": "0x01" + } + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "nonce": "0x00", + "balance": "0x01f923", + "code": "0x", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x01", + "balance": "0x3635c9adc5de996c36", + "code": "0x", + "storage": {} + } + }, + "sealEngine": "NoProof" + } +} \ No newline at end of file diff --git a/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_shanghai_blockchain.json b/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_shanghai_blockchain.json new file mode 100644 index 00000000000..8af9fb6be7a --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/fixtures/valid_simple_shanghai_blockchain.json @@ -0,0 +1,111 @@ +{ + "000/valid_blockchain_test/Shanghai": { + "_info": { + "filling-transition-tool": "evm version 1.13.12-unstable-253447a4-20240204" + }, + "network": "Shanghai", + "genesisRLP": "0xf9021df90217a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0aff9f63320a482f8c4e4f15f659e6a7ac382138fbbb6919243b0cba4c5988a5aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0", + "genesisBlockHeader": { + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x0000000000000000000000000000000000000000", + "stateRoot": "0xaff9f63320a482f8c4e4f15f659e6a7ac382138fbbb6919243b0cba4c5988a5a", + "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x00", + "number": "0x00", + "gasLimit": "0x016345785d8a0000", + "gasUsed": "0x00", + "timestamp": "0x00", + "extraData": "0x00", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x07", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "block_hash": "0xccb89b5b6043aa73114e6857f0783a02808ea6ff4cabd104a308eb4fe0114a9b" + }, + "blocks": [ + { + "rlp": "0xf90283f90219a0ccb89b5b6043aa73114e6857f0783a02808ea6ff4cabd104a308eb4fe0114a9ba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa019919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba0c598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0ab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8610c80a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0c0", + "blockHeader": { + "parentHash": "0xccb89b5b6043aa73114e6857f0783a02808ea6ff4cabd104a308eb4fe0114a9b", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "stateRoot": "0x19919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6", + "transactionsTrie": "0x8151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcb", + "receiptTrie": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x00", + "number": "0x01", + "gasLimit": "0x016345785d8a0000", + "gasUsed": "0xa861", + "timestamp": "0x0c", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x07", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "block_hash": "0xc970b6bcf304cd5c71d24548a7d65dd907a24a3b66229378e2ac42677c1eec2b" + }, + "blocknumber": "1", + "transactions": [ + { + "type": "0x00", + "chainId": "0x00", + "nonce": "0x00", + "gasPrice": "0x0a", + "gasLimit": "0x05f5e100", + "to": "0x1000000000000000000000000000000000000000", + "value": "0x00", + "data": "0x", + "v": "0x1b", + "r": "0x7e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37", + "s": "0x5f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + } + ], + "uncleHeaders": [], + "withdrawals": [] + } + ], + "lastblockhash": "0xc970b6bcf304cd5c71d24548a7d65dd907a24a3b66229378e2ac42677c1eec2b", + "pre": { + "0x1000000000000000000000000000000000000000": { + "nonce": "0x00", + "balance": "0x00", + "code": "0x4660015500", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x00", + "balance": "0x3635c9adc5dea00000", + "code": "0x", + "storage": {} + } + }, + "postState": { + "0x1000000000000000000000000000000000000000": { + "nonce": "0x00", + "balance": "0x00", + "code": "0x4660015500", + "storage": { + "0x01": "0x01" + } + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "nonce": "0x00", + "balance": "0x01f923", + "code": "0x", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "nonce": "0x01", + "balance": "0x3635c9adc5de996c36", + "code": "0x", + "storage": {} + } + }, + "sealEngine": "NoProof" + } +} \ No newline at end of file diff --git a/src/ethereum_test_tools/tests/test_consume/test_consume_engine_types.py b/src/ethereum_test_tools/tests/test_consume/test_consume_engine_types.py new file mode 100644 index 00000000000..2770a9ea0b0 --- /dev/null +++ b/src/ethereum_test_tools/tests/test_consume/test_consume_engine_types.py @@ -0,0 +1,219 @@ +""" +Test suite for `ethereum_test_tools.consume.types` module, with a focus on the engine payloads. +""" + +import json +import os +from typing import Any + +import pytest + +from ethereum_test_forks import Cancun, Fork, Merge, Shanghai # TODO: Replace with Paris +from ethereum_test_tools.common import ( + Account, + Block, + Fixture, + FixtureBlock, + TestAddress, + Transaction, + to_json, +) +from ethereum_test_tools.common.json import load_dataclass_from_json +from ethereum_test_tools.consume.types import EngineCancun, EngineParis, EngineShanghai +from ethereum_test_tools.filling import fill_test +from ethereum_test_tools.spec import BlockchainTest +from evm_transition_tool import GethTransitionTool + +common_execution_payload_fields = { + "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "receipts_root": "0xc598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0a", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", # noqa: E501 + "prev_randao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "number": 1, + "gas_limit": 100000000000000000, + "gas_used": 43105, + "timestamp": 12, + "extra_data": "0x", + "base_fee_per_gas": 7, + "transactions": [ + "0xf861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b" # noqa: E501 + ], +} + + +@pytest.mark.parametrize( + "fork, expected_json_fixture, expected_engine_new_payload, expected_enp_json", + [ + ( + Merge, # TODO: Replace with Paris + "valid_simple_merge_blockchain.json", + EngineParis.NewPayloadV1( + execution_payload=EngineParis.ExecutionPayloadV1( + **common_execution_payload_fields, + parent_hash=( + "0x86c6dc9cb7b8ada9e27b1cf16fd81f366a0ad8127f42ff13d778eb2ddf7eaa90" + ), + state_root=( + "0x19919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6" + ), + block_hash=( + "0xe9694e4b99986d312c6891cd7839b73d9e1b451537896818cefeeae97d7e3ea6" + ), + ) + ), + "valid_simple_merge_enp.json", + ), + ( + Shanghai, + "valid_simple_shanghai_blockchain.json", + EngineShanghai.NewPayloadV2( + execution_payload=EngineShanghai.ExecutionPayloadV2( + **common_execution_payload_fields, + parent_hash=( + "0xccb89b5b6043aa73114e6857f0783a02808ea6ff4cabd104a308eb4fe0114a9b" + ), + state_root=( + "0x19919608275963e6e20a1191996f5b19db8208dd8df54097cfd2b9cb14f682b6" + ), + block_hash=( + "0xc970b6bcf304cd5c71d24548a7d65dd907a24a3b66229378e2ac42677c1eec2b" + ), + withdrawals=[], + ) + ), + "valid_simple_shanghai_enp.json", + ), + ( + Cancun, + "valid_simple_cancun_blockchain.json", + EngineCancun.NewPayloadV3( + execution_payload=EngineCancun.ExecutionPayloadV3( + **common_execution_payload_fields, + parent_hash=( + "0xda9249b7aff004bcdfadfb5f668899746e36a5eee8197d1589deb4a3842251ce" + ), + state_root=( + "0x3d760432d38fbf795fb9addd6b25a692d82498bd5f7b703a6da6d8647c5b7820" + ), + block_hash=( + "0x546546d8a2d99b3135a47debdfc708e6a2199b8d90e43325d2c0b3adc3613709" + ), + withdrawals=[], + blob_gas_used=0, + excess_blob_gas=0, + ), + expected_blob_versioned_hashes=[], + parent_beacon_block_root=( + "0x0000000000000000000000000000000000000000000000000000000000000000" + ), + ), + "valid_simple_cancun_enp.json", + ), + ], +) +def test_valid_engine_new_payload_fields( + fork: Fork, + expected_json_fixture: str, + expected_engine_new_payload: Any, + expected_enp_json: str, +): + """ + Test ... + """ + blockchain_test = BlockchainTest( + pre={ + 0x1000000000000000000000000000000000000000: Account(code="0x4660015500"), + TestAddress: Account(balance=1000000000000000000000), + }, + post={ + "0x1000000000000000000000000000000000000000": Account( + code="0x4660015500", storage={"0x01": "0x01"} + ), + }, + blocks=[ + Block( + txs=[ + Transaction( + ty=0x0, + chain_id=0x0, + nonce=0, + to="0x1000000000000000000000000000000000000000", + gas_limit=100000000, + gas_price=10, + protected=False, + ) + ] + ) + ], + ) + # Create a blockchain test fixture + fixture: Fixture = { + f"000/valid_blockchain_test/{fork}": fill_test( + t8n=GethTransitionTool(), + test_spec=blockchain_test, + fork=fork, + spec=None, + ), + } + # Sanity check the fixture is equal to the expected + with open( + os.path.join( + "src", + "ethereum_test_tools", + "tests", + "test_consume", + "fixtures", + expected_json_fixture, + ) + ) as f: + expected = json.load(f) + fixture_json = to_json(fixture) + assert fixture_json == expected + + # Load json fixture into Fixture type + for _, fixture_data in fixture_json.items(): + fixture = load_dataclass_from_json(Fixture, fixture_data) + + # Get fixture blocks + fixture_blocks = [ + load_dataclass_from_json(FixtureBlock, block.get("rlp_decoded", block)) + for block in fixture.blocks + ] + + # Extract the engine payloads from the fixture blocks + # Ideally we don't know the fork at this point + for fixture_block in fixture_blocks: + fork = globals()[fixture.fork] + version = fork.engine_new_payload_version( + fixture_block.block_header.number, fixture_block.block_header.timestamp + ) + if version == 1: + PayloadClass = EngineParis.NewPayloadV1 + elif version == 2: + PayloadClass = EngineShanghai.NewPayloadV2 + elif version == 3: + PayloadClass = EngineCancun.NewPayloadV3 + else: + ValueError(f"Unexpected payload version: {version}") + continue + + engine_new_payload = PayloadClass.from_fixture_block(fixture_block) + + # Compare the engine payloads with the expected payloads + assert engine_new_payload == expected_engine_new_payload + + # Check the json representation of the engine payloads that would be sent over json-rpc + with open( + os.path.join( + "src", + "ethereum_test_tools", + "tests", + "test_consume", + "engine_json", + expected_enp_json, + ) + ) as f: + expected = json.load(f) + + print(engine_new_payload.to_json_rpc()) + assert engine_new_payload.to_json_rpc() == expected diff --git a/src/ethereum_test_tools/tests/test_filler.py b/src/ethereum_test_tools/tests/test_filler.py index f98a18ef5e3..35f196e506d 100644 --- a/src/ethereum_test_tools/tests/test_filler.py +++ b/src/ethereum_test_tools/tests/test_filler.py @@ -81,8 +81,8 @@ def test_make_genesis(fork: Fork, hash: bytes): # noqa: D103 t8n, fork, ) - assert genesis.hash is not None - assert genesis.hash.startswith(hash) + assert genesis.block_hash is not None + assert genesis.block_hash.startswith(hash) @pytest.mark.parametrize( @@ -418,9 +418,9 @@ def test_fill_blockchain_valid_txs( ), } - # We start genesis with a baseFee of 1000 + # We start genesis with a baseFeePerGas of 1000 genesis_environment = Environment( - base_fee=1000, + base_fee_per_gas=1000, coinbase="0xba5e000000000000000000000000000000000000", ) @@ -767,9 +767,9 @@ def test_fill_blockchain_invalid_txs( ), } - # We start genesis with a baseFee of 1000 + # We start genesis with a baseFeePerGas of 1000 genesis_environment = Environment( - base_fee=1000, + base_fee_per_gas=1000, coinbase="0xba5e000000000000000000000000000000000000", ) diff --git a/src/ethereum_test_tools/tests/test_types.py b/src/ethereum_test_tools/tests/test_types.py index d725354d8d8..029b2bf5446 100644 --- a/src/ethereum_test_tools/tests/test_types.py +++ b/src/ethereum_test_tools/tests/test_types.py @@ -439,10 +439,10 @@ def test_account_merge( coinbase=0x1234, difficulty=0x5, prev_randao=0x6, - base_fee=0x7, + base_fee_per_gas=0x7, parent_difficulty=0x8, parent_timestamp=0x9, - parent_base_fee=0xA, + parent_base_fee_per_gas=0xA, parent_gas_used=0xB, parent_gas_limit=0xC, parent_ommers_hash=0xD, @@ -737,15 +737,15 @@ def test_account_merge( coinbase=Address(2), state_root=Hash(3), transactions_root=Hash(4), - receipt_root=Hash(5), - bloom=Bloom(6), + receipts_root=Hash(5), + logs_bloom=Bloom(6), difficulty=7, number=8, gas_limit=9, gas_used=10, timestamp=11, extra_data=Bytes([12]), - mix_digest=Hash(13), + prev_randao=Hash(13), nonce=HeaderNonce(14), ), { @@ -774,21 +774,21 @@ def test_account_merge( coinbase=Address(2), state_root=Hash(3), transactions_root=Hash(4), - receipt_root=Hash(5), - bloom=Bloom(6), + receipts_root=Hash(5), + logs_bloom=Bloom(6), difficulty=7, number=8, gas_limit=9, gas_used=10, timestamp=11, extra_data=Bytes([12]), - mix_digest=Hash(13), + prev_randao=Hash(13), nonce=HeaderNonce(14), - base_fee=15, + base_fee_per_gas=15, withdrawals_root=Hash(16), blob_gas_used=17, excess_blob_gas=18, - hash=Hash(19), + block_hash=Hash(19), ), { "parentHash": Hash(0).hex(), @@ -822,21 +822,21 @@ def test_account_merge( coinbase=Address(2), state_root=Hash(3), transactions_root=Hash(4), - receipt_root=Hash(5), - bloom=Bloom(6), + receipts_root=Hash(5), + logs_bloom=Bloom(6), difficulty=7, number=8, gas_limit=9, gas_used=10, timestamp=11, extra_data=Bytes([12]), - mix_digest=Hash(13), + prev_randao=Hash(13), nonce=HeaderNonce(14), - base_fee=15, + base_fee_per_gas=15, withdrawals_root=Hash(16), blob_gas_used=17, excess_blob_gas=18, - hash=Hash(19), + block_hash=Hash(19), ), transactions=[ Transaction( @@ -907,21 +907,21 @@ def test_account_merge( coinbase=Address(2), state_root=Hash(3), transactions_root=Hash(4), - receipt_root=Hash(5), - bloom=Bloom(6), + receipts_root=Hash(5), + logs_bloom=Bloom(6), difficulty=7, number=8, gas_limit=9, gas_used=10, timestamp=11, extra_data=Bytes([12]), - mix_digest=Hash(13), + prev_randao=Hash(13), nonce=HeaderNonce(14), - base_fee=15, + base_fee_per_gas=15, withdrawals_root=Hash(16), blob_gas_used=17, excess_blob_gas=18, - hash=Hash(19), + block_hash=Hash(19), ), transactions=[ Transaction( @@ -999,21 +999,21 @@ def test_account_merge( coinbase=Address(2), state_root=Hash(3), transactions_root=Hash(4), - receipt_root=Hash(5), - bloom=Bloom(6), + receipts_root=Hash(5), + logs_bloom=Bloom(6), difficulty=7, number=8, gas_limit=9, gas_used=10, timestamp=11, extra_data=Bytes([12]), - mix_digest=Hash(13), + prev_randao=Hash(13), nonce=HeaderNonce(14), - base_fee=15, + base_fee_per_gas=15, withdrawals_root=Hash(16), blob_gas_used=17, excess_blob_gas=18, - hash=Hash(19), + block_hash=Hash(19), ), transactions=[ Transaction( diff --git a/src/evm_transition_tool/tests/test_evaluate.py b/src/evm_transition_tool/tests/test_evaluate.py index 171fd5e5455..4d846560279 100644 --- a/src/evm_transition_tool/tests/test_evaluate.py +++ b/src/evm_transition_tool/tests/test_evaluate.py @@ -15,7 +15,7 @@ @pytest.mark.parametrize("t8n", [GethTransitionTool()]) @pytest.mark.parametrize("fork", [London, Istanbul]) @pytest.mark.parametrize( - "alloc,base_fee,hash", + "alloc,base_fee_per_gas,hash", [ ( { @@ -68,14 +68,14 @@ def test_calc_state_root( # noqa: D103 t8n: TransitionTool, fork: Fork, alloc: Dict, - base_fee: int | None, + base_fee_per_gas: int | None, hash: bytes, ) -> None: class TestEnv: - base_fee: int | None + base_fee_per_gas: int | None env = TestEnv() - env.base_fee = base_fee + env.base_fee_per_gas = base_fee_per_gas assert t8n.calc_state_root(alloc=alloc, fork=fork)[1].startswith(hash) diff --git a/src/evm_transition_tool/transition_tool.py b/src/evm_transition_tool/transition_tool.py index f45f25ec8df..5464c261f89 100644 --- a/src/evm_transition_tool/transition_tool.py +++ b/src/evm_transition_tool/transition_tool.py @@ -1,6 +1,7 @@ """ Transition tool abstract class. """ + import json import os import shutil @@ -555,7 +556,7 @@ def calc_state_root( "currentTimestamp": "0", } - if fork.header_base_fee_required(0, 0): + if fork.header_base_fee_per_gas_required(0, 0): env["currentBaseFee"] = "7" if fork.header_prev_randao_required(0, 0): diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py index df7d3bb32b8..442658bf73b 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py @@ -22,6 +22,7 @@ cases. """ # noqa: E501 + import itertools from typing import Dict, Iterator, List, Mapping, Optional, Tuple @@ -107,29 +108,31 @@ def block_fee_per_blob_gas( # noqa: D103 @pytest.fixture -def block_base_fee() -> int: # noqa: D103 +def block_base_fee_per_gas() -> int: # noqa: D103 return 7 @pytest.fixture def env( # noqa: D103 parent_excess_blob_gas: int, - block_base_fee: int, + block_base_fee_per_gas: int, parent_blobs: int, ) -> Environment: return Environment( - excess_blob_gas=parent_excess_blob_gas - if parent_blobs == 0 - else parent_excess_blob_gas + Spec.TARGET_BLOB_GAS_PER_BLOCK, - base_fee=block_base_fee, + excess_blob_gas=( + parent_excess_blob_gas + if parent_blobs == 0 + else parent_excess_blob_gas + Spec.TARGET_BLOB_GAS_PER_BLOCK + ), + base_fee_per_gas=block_base_fee_per_gas, ) @pytest.fixture def tx_max_fee_per_gas( # noqa: D103 - block_base_fee: int, + block_base_fee_per_gas: int, ) -> int: - return block_base_fee + return block_base_fee_per_gas @pytest.fixture @@ -330,9 +333,7 @@ def test_correct_excess_blob_gas_calculation( 2**32, # blob gas cost 2^32 2**64 // Spec.GAS_PER_BLOB, # Data tx wei cost 2^64 2**64, # blob gas cost 2^64 - ( - 120_000_000 * (10**18) // Spec.GAS_PER_BLOB - ), # Data tx wei is current total Ether supply + 120_000_000 * (10**18) // Spec.GAS_PER_BLOB, # Data tx wei is current total Ether supply ] ] diff --git a/whitelist.txt b/whitelist.txt index 1536055a9b3..e32dfa429fd 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -272,6 +272,8 @@ util utils v0 v1 +v2 +v3 validator venv visualstudio