Skip to content

fix(forks,tests): EIP-7251, EIP-7002 Spec Updates #1024

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
Dec 30, 2024
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
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ Test fixtures for use by clients are available for each release on the [Github r
- ✨ Add a default location for evm logs (`--evm-dump-dir`) when filling tests ([#999](https://github.com/ethereum/execution-spec-tests/pull/999)).
- ✨ Slow tests now have greater timeout when making a request to the T8N server ([#1037](https://github.com/ethereum/execution-spec-tests/pull/1037)).
- ✨ Introduce [`fork_covariant_parametrize`](https://ethereum.github.io/execution-spec-tests/main/writing_tests/test_markers/#custom-fork-covariant-markers) helper function ([#1019](https://github.com/ethereum/execution-spec-tests/pull/1019)).
- 🔀 Update EIP-7251 according to [spec updates](https://github.com/ethereum/EIPs/pull/9127) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024))
- 🔀 Update EIP-7002 according to [spec updates](https://github.com/ethereum/EIPs/pull/9119) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024))

### 🔧 EVM Tools

Expand Down
Binary file not shown.
8 changes: 4 additions & 4 deletions src/ethereum_test_forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,8 +984,8 @@ def system_contracts(cls, block_number: int = 0, timestamp: int = 0) -> List[Add
"""Prague introduces the system contracts for EIP-6110, EIP-7002, EIP-7251 and EIP-2935."""
return [
Address(0x00000000219AB540356CBB839CBE05303D7705FA),
Address(0x09FC772D0857550724B07B850A4323F39112AAAA),
Address(0x01ABEA29659E5E97C95107F20BB753CD3E09BBBB),
Address(0x0C15F14308530B7CDB8460094BBB9CC28B9AAAAA),
Address(0x00431F263CE400F4455C2DCF564E53007CA4BBBB),
Address(0x0AAE40965E6800CD9B1F4B05FF21581047E3F91E),
] + super(Prague, cls).system_contracts(block_number, timestamp)

Expand Down Expand Up @@ -1104,7 +1104,7 @@ def pre_allocation_blockchain(cls) -> Mapping:
with open(CURRENT_FOLDER / "contracts" / "withdrawal_request.bin", mode="rb") as f:
new_allocation.update(
{
0x09FC772D0857550724B07B850A4323F39112AAAA: {
0x0C15F14308530B7CDB8460094BBB9CC28B9AAAAA: {
"nonce": 1,
"code": f.read(),
},
Expand All @@ -1115,7 +1115,7 @@ def pre_allocation_blockchain(cls) -> Mapping:
with open(CURRENT_FOLDER / "contracts" / "consolidation_request.bin", mode="rb") as f:
new_allocation.update(
{
0x01ABEA29659E5E97C95107F20BB753CD3E09BBBB: {
0x00431F263CE400F4455C2DCF564E53007CA4BBBB: {
"nonce": 1,
"code": f.read(),
},
Expand Down
2 changes: 2 additions & 0 deletions src/ethereum_test_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
Yul,
YulCompiler,
)
from .utility.generators import generate_system_contract_deploy_test
from .utility.pytest import extend_with_defaults

__all__ = (
Expand Down Expand Up @@ -155,6 +156,7 @@
"compute_create2_address",
"compute_eofcreate_address",
"extend_with_defaults",
"generate_system_contract_deploy_test",
"keccak256",
"vm",
)
181 changes: 181 additions & 0 deletions src/ethereum_test_tools/utility/generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
"""Test generator decorators."""

import json
from enum import Enum
from pathlib import Path
from typing import Dict, Generator, List, Protocol, Tuple

import pytest

from ethereum_test_base_types import Account, Address
from ethereum_test_forks import Fork
from ethereum_test_specs import BlockchainTestFiller
from ethereum_test_specs.blockchain import Block, Header
from ethereum_test_types import Alloc, Transaction


class SystemContractDeployTestFunction(Protocol):
"""
Represents a function to be decorated with the `generate_system_contract_deploy_test`
decorator.
"""

def __call__(
self,
*,
fork: Fork,
pre: Alloc,
) -> Generator[Tuple[Transaction | None, Header | None], None, None]:
"""
Args:
fork (Fork): The fork to test.
pre (Alloc): The pre state of the blockchain.

Yields:
Tuple[Transaction | None, Header | None]: Once per block to add after the contract is
deployed, with a single transaction to execute and the header object used to
verify the block.

"""
...


class DeploymentTestType(Enum):
"""Represents the type of deployment test."""

DEPLOY_BEFORE_FORK = "deploy_before_fork"
DEPLOY_AFTER_FORK = "deploy_after_fork"


def generate_system_contract_deploy_test(
fork: Fork,
tx_json_path: Path,
expected_deploy_address: Address,
expected_system_contract_storage: Dict | None,
):
"""
Generate a test that verifies the correct deployment of a system contract.

Generates two tests:
- One that deploys the contract before the fork.
- One that deploys the contract after the fork.

Args:
fork (Fork): The fork to test.
tx_json_path (Path): Path to the JSON file with the transaction to deploy the system
contract.
Providing a JSON file is useful to copy-paste the transaction from the EIP.
expected_deploy_address (Address): The expected address of the deployed contract.
expected_system_contract_storage (Dict): The expected storage of the system contract.

"""
with open(tx_json_path, mode="r") as f:
tx_json = json.loads(f.read())
if "gasLimit" not in tx_json and "gas" in tx_json:
tx_json["gasLimit"] = tx_json["gas"]
del tx_json["gas"]
if "protected" not in tx_json:
tx_json["protected"] = False
deploy_tx = Transaction.model_validate(tx_json).with_signature_and_sender() # type: ignore
gas_price = deploy_tx.gas_price
assert gas_price is not None
deployer_required_balance = deploy_tx.gas_limit * gas_price
deployer_address = deploy_tx.sender

def decorator(func: SystemContractDeployTestFunction):
@pytest.mark.parametrize(
"test_type",
[
pytest.param(DeploymentTestType.DEPLOY_BEFORE_FORK),
pytest.param(DeploymentTestType.DEPLOY_AFTER_FORK),
],
ids=lambda x: x.name.lower(),
)
@pytest.mark.execute(pytest.mark.skip(reason="modifies pre-alloc"))
@pytest.mark.valid_at_transition_to(fork.name())
def wrapper(
blockchain_test: BlockchainTestFiller,
pre: Alloc,
test_type: DeploymentTestType,
fork: Fork,
):
assert deployer_address is not None
assert deploy_tx.created_contract == expected_deploy_address
blocks: List[Block] = []

if test_type == DeploymentTestType.DEPLOY_BEFORE_FORK:
blocks = [
Block( # Deployment block
txs=[deploy_tx],
timestamp=14_999,
),
Block( # Empty block on fork
txs=[],
timestamp=15_000,
),
]
elif test_type == DeploymentTestType.DEPLOY_AFTER_FORK:
blocks = [
Block( # Empty block on fork
txs=[],
timestamp=15_000,
),
Block( # Deployment block
txs=[deploy_tx],
timestamp=15_001,
),
]

for tx_header_verify in func(fork=fork, pre=pre):
txs = []
if tx_header_verify[0] is not None:
txs.append(tx_header_verify[0])
header_verify = tx_header_verify[1]
blocks.append(
Block(
txs=txs,
header_verify=header_verify,
)
)

pre[expected_deploy_address] = Account(
code=b"", # Remove the code that is automatically allocated on the fork
nonce=0,
balance=0,
)
pre[deployer_address] = Account(
balance=deployer_required_balance,
)

expected_deploy_address_int = int.from_bytes(expected_deploy_address, "big")

post = {}
fork_pre_allocation = fork.pre_allocation_blockchain()
assert expected_deploy_address_int in fork_pre_allocation
expected_code = fork_pre_allocation[expected_deploy_address_int]["code"]
if expected_system_contract_storage is None:
post[expected_deploy_address] = Account(
code=expected_code,
nonce=1,
)
else:
post[expected_deploy_address] = Account(
storage=expected_system_contract_storage,
code=expected_code,
nonce=1,
)
post[deployer_address] = Account(
nonce=1,
)
blockchain_test(
pre=pre,
blocks=blocks,
post=post,
)

wrapper.__name__ = func.__name__ # type: ignore
wrapper.__doc__ = func.__doc__ # type: ignore

return wrapper

return decorator
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
"maxPriorityFeePerGas": null,
"maxFeePerGas": null,
"value": "0x0",
"input": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f556101f480602d5f395ff33373fffffffffffffffffffffffffffffffffffffffe1460c7573615156028575f545f5260205ff35b36603814156101f05760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f057600182026001905f5b5f821115608057810190830284830290049160010191906065565b9093900434106101f057600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160db575060105b5f5b81811461017f5780604c02838201600302600401805490600101805490600101549160601b83528260140152807fffffffffffffffffffffffffffffffff0000000000000000000000000000000016826034015260401c906044018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160dd565b9101809214610191579060025561019c565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101c957505f5b6001546002828201116101de5750505f6101e4565b01600290035b5f555f600155604c025ff35b5f5ffd",
"input": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f556101f880602d5f395ff33373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
"v": "0x1b",
"r": "0x539",
"s": "0x10e740537d4d36b9",
"hash": "0x1cd8bf929988b27b07ba1c7b898b396c08c484bb0db83fdeb992aa21b5cdf0ce",
"s": "0xeb793ed1dcd82833",
"hash": "0xe89c48ef3308192a0768aefaa5128559e68ab87b5b9a6d113824551867746a20",
"protected": false
}
6 changes: 3 additions & 3 deletions tests/prague/eip7002_el_triggerable_withdrawals/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ReferenceSpec:
version: str


ref_spec_7002 = ReferenceSpec("EIPS/eip-7002.md", "9fe721f56f45bd5cf2d2958c0e6867aa81f82ebc")
ref_spec_7002 = ReferenceSpec("EIPS/eip-7002.md", "25cca6506df8370157513e4e864fd174cafd3562")


# Constants
Expand All @@ -30,8 +30,8 @@ class Spec:
out.
"""

WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS = 0x09FC772D0857550724B07B850A4323F39112AAAA
WITHDRAWAL_REQUEST_PREDEPLOY_SENDER = Address(0x57B8C3C2766D0623EA0A499365A6F5A26AD38B47)
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS = 0x0C15F14308530B7CDB8460094BBB9CC28B9AAAAA
WITHDRAWAL_REQUEST_PREDEPLOY_SENDER = Address(0xA05D9EED37862DAB22B002B8F6668B8FB0C4D798)
SYSTEM_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE

EXCESS_WITHDRAWAL_REQUESTS_STORAGE_SLOT = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002).
Test system contract deployment for [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002).
""" # noqa: E501

from os.path import realpath
from pathlib import Path
from typing import Generator, Tuple

from ethereum_test_forks import Fork, Prague
from ethereum_test_tools import (
Address,
Alloc,
Header,
Requests,
Transaction,
generate_system_contract_deploy_test,
)

from .helpers import WithdrawalRequest
from .spec import Spec, ref_spec_7002

REFERENCE_SPEC_GIT_PATH = ref_spec_7002.git_path
REFERENCE_SPEC_VERSION = ref_spec_7002.version


@generate_system_contract_deploy_test(
fork=Prague,
tx_json_path=Path(realpath(__file__)).parent / "contract_deploy_tx.json",
expected_deploy_address=Address(Spec.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS),
expected_system_contract_storage=None,
)
def test_system_contract_deployment(
*,
fork: Fork,
pre: Alloc,
) -> Generator[Tuple[Transaction, Header], None, None]:
"""Verify calling the withdrawals system contract after deployment."""
sender = pre.fund_eoa()
withdrawal_request = WithdrawalRequest(
validator_pubkey=0x01,
amount=1,
fee=Spec.get_fee(0),
source_address=sender,
)
pre.fund_address(sender, withdrawal_request.value)
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
test_transaction_gas = intrinsic_gas_calculator(calldata=withdrawal_request.calldata)

test_transaction = Transaction(
data=withdrawal_request.calldata,
gas_limit=test_transaction_gas * 10,
to=Spec.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
sender=sender,
value=withdrawal_request.value,
)

yield from [
(
test_transaction,
Header(
requests_hash=Requests(withdrawal_request),
),
),
]
6 changes: 3 additions & 3 deletions tests/prague/eip7251_consolidations/contract_deploy_tx.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
"maxPriorityFeePerGas": null,
"maxFeePerGas": null,
"value": "0x0",
"input": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f5561019e80602d5f395ff33373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
"input": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f5561019e80602d5f395ff33373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
"v": "0x1b",
"r": "0x539",
"s": "0x832fdd8c49a416f1",
"hash": "0x5e174f35e55bc53c898f3c5e315d81e054363363a0e95dfd6e43c23e8ebb9407",
"s": "0x332601ef36aa2ce9",
"hash": "0xc7d223eb06267248bcd21f7af0223c8d467ef7e95ff51cef84c616973692169f",
"protected": false
}
8 changes: 4 additions & 4 deletions tests/prague/eip7251_consolidations/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ReferenceSpec:
version: str


ref_spec_7251 = ReferenceSpec("EIPS/eip-7251.md", "18af57e74e4e862da5cbb8140aeb24128088f4e2")
ref_spec_7251 = ReferenceSpec("EIPS/eip-7251.md", "cc6ed420006c13b6ef64b7987badc2966ad4508f")


# Constants
Expand All @@ -24,8 +24,8 @@ class Spec:
https://eips.ethereum.org/EIPS/eip-7251#execution-layer.
"""

CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS = 0x01ABEA29659E5E97C95107F20BB753CD3E09BBBB
CONSOLIDATION_REQUEST_PREDEPLOY_SENDER = Address(0x81E9AFA909FE8B57AF2A6FD18862AE9DAE3163F4)
CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS = 0x00431F263CE400F4455C2DCF564E53007CA4BBBB
CONSOLIDATION_REQUEST_PREDEPLOY_SENDER = Address(0xE24B968AB4319A580D9FFC7AC29466894FEEB361)
SYSTEM_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE

EXCESS_CONSOLIDATION_REQUESTS_STORAGE_SLOT = 0
Expand All @@ -40,7 +40,7 @@ class Spec:
4 # The start memory slot of the in-state consolidation request message queue
)
MAX_CONSOLIDATION_REQUESTS_PER_BLOCK = (
1 # Maximum number of consolidation requests that can be de-queued into a block
2 # Maximum number of consolidation requests that can be de-queued into a block
)
TARGET_CONSOLIDATION_REQUESTS_PER_BLOCK = 1
MIN_CONSOLIDATION_REQUEST_FEE = 1
Expand Down
Loading
Loading