Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fw): verkle pydantic rebase and t8n changes #507

Draft
wants to merge 3 commits into
base: verkle/main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 42 additions & 0 deletions docs/consuming_tests/common_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,45 @@ Fork type is represented as a JSON string that can be set to one of the followin
- Terminal Total Difficulty: `0x00`
- Shanghai Time: `0x00`
- Cancun Time: `0x00`

### `"Prague"`

- Chain ID: `0x01`
- Homestead Block: `0x00`
- EIP150 Block: `0x00`
- EIP155 Block: `0x00`
- EIP158 Block: `0x00`
- DAO Fork Block: `0x00`
- Byzantium Block: `0x00`
- Constantinople Block: `0x00`
- Constantinople Fix Block: `0x00`
- Istanbul Block: `0x00`
- Muir Glacier Block: `0x00`
- Berlin Block: `0x00`
- London Block: `0x00`
- Arrow Glacier Block: `0x00`
- Gray Glacier Block: `0x00`
- Terminal Total Difficulty: `0x00`
- Shanghai Time: `0x00`
- Prague Time: `0x00`

### `"ShanghaiToPragueVerkleTransition"`

- Chain ID: `0x01`
- Homestead Block: `0x00`
- EIP150 Block: `0x00`
- EIP155 Block: `0x00`
- EIP158 Block: `0x00`
- DAO Fork Block: `0x00`
- Byzantium Block: `0x00`
- Constantinople Block: `0x00`
- Constantinople Fix Block: `0x00`
- Istanbul Block: `0x00`
- Muir Glacier Block: `0x00`
- Berlin Block: `0x00`
- London Block: `0x00`
- Arrow Glacier Block: `0x00`
- Gray Glacier Block: `0x00`
- Terminal Total Difficulty: `0x00`
- Shanghai Time: `0x00`
- Prague Time: `0x01`
2 changes: 2 additions & 0 deletions src/ethereum_test_forks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
Paris,
Prague,
Shanghai,
ShanghaiEIP6800,
)
from .forks.transition import (
BerlinToLondonAt5,
Expand Down Expand Up @@ -60,6 +61,7 @@
"MuirGlacier",
"Shanghai",
"ShanghaiToCancunAtTime15k",
"ShanghaiEIP6800",
"Cancun",
"Prague",
"get_transition_forks",
Expand Down
20 changes: 20 additions & 0 deletions src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,26 @@ def pre_allocation_blockchain(cls) -> Mapping:
"""
pass

@classmethod
@abstractmethod
def environment_verkle_conversion_starts(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if the fork starts the verkle conversion process.
"""
pass

@classmethod
@abstractmethod
def environment_verkle_conversion_completed(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if verkle conversion must have been completed by this fork.
"""
pass

# Engine API information abstract methods
@classmethod
@abstractmethod
Expand Down
53 changes: 53 additions & 0 deletions src/ethereum_test_forks/forks/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
Constant values used by the forks.
"""

from typing import Dict, Generator, Iterator, Mapping, Tuple

from Crypto.Hash import SHA256

# Verkle conversion MPT constants
MAX_ACCOUNTS = 1000
MAX_NONCE = 2**64 - 1
MAX_BALANCE = 2**256 - 1
MAX_STORAGE_SLOTS_PER_ACCOUNT = 1000
MAX_ACCOUNT_CODE_SIZE = 2**14 + 2**13 # EIP-170


def seed_generator(seed: int) -> Generator[int, None, None]:
seed = int.from_bytes(
bytes=SHA256.new(data=seed.to_bytes(length=256, byteorder="big")).digest(), byteorder="big"
)
while True:
yield seed
seed = int.from_bytes(
bytes=SHA256.new(data=seed.to_bytes(length=256, byteorder="big")).digest(),
byteorder="big",
)


def storage_generator(
seed: Iterator[int], max_slots: int
) -> Generator[Tuple[int, int], None, None]:
MAX_KEY_VALUE = 2**256 - 1
for _ in range(max_slots):
yield next(seed) % MAX_KEY_VALUE, next(seed) % MAX_KEY_VALUE


def account_generator(
seed: Iterator[int], max_accounts: int
) -> Generator[Tuple[int, Dict[str, str | int | Dict[int, int]]], None, None]:
for _ in range(max_accounts):
storage_g = storage_generator(seed, next(seed) % MAX_STORAGE_SLOTS_PER_ACCOUNT)
yield next(seed) % 2**160, {
"nonce": next(seed) % MAX_NONCE,
"balance": next(seed) % MAX_BALANCE,
"storage": {k: v for k, v in storage_g},
"code": "0x" + "00" * 32,
}


VERKLE_PRE_ALLOCATION: Mapping = {
addr: account
for addr, account in account_generator(seed=seed_generator(0), max_accounts=MAX_ACCOUNTS)
}
65 changes: 64 additions & 1 deletion src/ethereum_test_forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,24 @@ def pre_allocation_blockchain(cls) -> Mapping:
"""
return {}

@classmethod
def environment_verkle_conversion_starts(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if the fork starts the verkle conversion process.
"""
return False

@classmethod
def environment_verkle_conversion_completed(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Returns true if verkle conversion must have been completed by this fork.
"""
return False


class Homestead(Frontier):
"""
Expand Down Expand Up @@ -394,6 +412,23 @@ def engine_new_payload_version(
"""
return 2

@classmethod
def pre_allocation_blockchain(cls) -> Mapping:
"""
Prague requires pre-allocation of the history storage contract for EIP-2935 on blockchain
type tests.
"""
new_allocation = {
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE: {
"nonce": 1,
"code": (
"0x60203611603157600143035f35116029575f35612000014311602957612000"
"5f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00"
),
}
}
return new_allocation | super(Shanghai, cls).pre_allocation_blockchain()


class Cancun(Shanghai):
"""
Expand Down Expand Up @@ -604,7 +639,35 @@ def engine_forkchoice_updated_version(
return 3


class CancunEIP7692( # noqa: SC200
class ShanghaiEIP6800(
Shanghai,
transition_tool_name="Prague", # Geth enables (only) Verkle at Prague
blockchain_test_network_name="Prague", # Geth enables (only) Verkle at Prague
solc_name="shanghai",
):
"""
Shanghai + EIP-6800 (Verkle) fork
"""

@classmethod
def is_deployed(cls) -> bool:
"""
Flags that the fork has not been deployed to mainnet; it is under active
development.
"""
return False

@classmethod
def environment_verkle_conversion_starts(
cls, block_number: int = 0, timestamp: int = 0
) -> bool:
"""
Verkle conversion starts in this fork.
"""
return True


class CancunEIP7692(
Cancun,
transition_tool_name="Prague", # Evmone enables (only) EOF at Prague
blockchain_test_network_name="Prague", # Evmone enables (only) EOF at Prague
Expand Down
37 changes: 35 additions & 2 deletions src/ethereum_test_forks/forks/transition.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""
List of all transition fork definitions.
"""

from ..transition_base_fork import transition_fork
from .forks import Berlin, Cancun, London, Paris, Prague, Shanghai
from .forks import Berlin, Cancun, London, Paris, Prague, Shanghai, ShanghaiEIP6800


# Transition Forks
@transition_fork(to_fork=London, at_block=5)
class BerlinToLondonAt5(Berlin):
"""
Expand Down Expand Up @@ -40,3 +40,36 @@ class CancunToPragueAtTime15k(Cancun):
"""

pass


@transition_fork(to_fork=ShanghaiEIP6800, at_timestamp=32, always_execute=True)
class ShanghaiToVerkleAtTime32(Shanghai):
"""
Shanghai to Verkle transition at Timestamp 32 (transition enabled for all tests)
"""

pass


# TODO: Uncomment and utilize when testing the Verkle tree conversion with stride enabled.
# from typing import Mapping
# from .constants import VERKLE_PRE_ALLOCATION
# @transition_fork(to_fork=Prague, at_timestamp=1, always_execute=True)
# class ShanghaiToPragueVerkleTransition(Shanghai):
# """
# Shanghai to Prague transition at Timestamp 1
#
# This is a special case where the transition happens on the first block after genesis, used
# to test the MPT to Verkle tree conversion.
#
# We run all tests with this transition fork.
# """
#
# @classmethod
# def pre_allocation(cls) -> Mapping:
# """
# Pre-allocates a big state full of accounts and storage to test the MPT to Verkle tree
# conversion.
# """
#
# return VERKLE_PRE_ALLOCATION | super(Shanghai, cls).pre_allocation()
8 changes: 7 additions & 1 deletion src/ethereum_test_forks/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Helper methods to resolve forks during test filling
"""

from typing import List, Optional

from semver import Version
Expand Down Expand Up @@ -32,6 +33,9 @@ def get_forks() -> List[Fork]:
continue
if issubclass(fork, BaseFork) and fork is not BaseFork:
all_forks.append(fork)

all_forks += get_transition_forks(always_execute=True)

return all_forks


Expand Down Expand Up @@ -87,7 +91,7 @@ def get_closest_fork_with_solc_support(fork: Fork, solc_version: Version) -> Opt
)


def get_transition_forks() -> List[Fork]:
def get_transition_forks(always_execute: bool = False) -> List[Fork]:
"""
Returns all the transition forks
"""
Expand All @@ -98,6 +102,8 @@ def get_transition_forks() -> List[Fork]:
if not isinstance(fork, type):
continue
if issubclass(fork, TransitionBaseClass) and issubclass(fork, BaseFork):
if always_execute and not fork.always_execute():
continue
transition_forks.append(fork)

return transition_forks
Expand Down
13 changes: 12 additions & 1 deletion src/ethereum_test_forks/transition_base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ def transitions_from(cls) -> Fork:
"""
raise Exception("Not implemented")

@classmethod
def always_execute(cls) -> bool:
"""
Whether the transition fork should be treated as a normal fork and all tests should
be filled with it.
"""
raise Exception("Not implemented")


def base_fork_abstract_methods() -> List[str]:
"""
Expand All @@ -38,7 +46,9 @@ def base_fork_abstract_methods() -> List[str]:
return list(getattr(BaseFork, "__abstractmethods__"))


def transition_fork(to_fork: Fork, at_block: int = 0, at_timestamp: int = 0):
def transition_fork(
to_fork: Fork, at_block: int = 0, at_timestamp: int = 0, always_execute: bool = False
):
"""
Decorator to mark a class as a transition fork.
"""
Expand Down Expand Up @@ -102,6 +112,7 @@ def transition_method(

NewTransitionClass.transitions_to = lambda: to_fork # type: ignore
NewTransitionClass.transitions_from = lambda: from_fork # type: ignore
NewTransitionClass.always_execute = lambda: always_execute # type: ignore
NewTransitionClass.fork_at = lambda block_number=0, timestamp=0: ( # type: ignore
to_fork if block_number >= at_block and timestamp >= at_timestamp else from_fork
)
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 @@ -31,6 +31,7 @@
TestPrivateKey,
TestPrivateKey2,
Transaction,
VerkleTree,
Withdrawal,
WithdrawalRequest,
add_kzg_version,
Expand Down Expand Up @@ -113,6 +114,7 @@
"TransactionException",
"Withdrawal",
"WithdrawalRequest",
"VerkleTree",
"Yul",
"YulCompiler",
"add_kzg_version",
Expand Down
2 changes: 2 additions & 0 deletions src/ethereum_test_tools/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
Requests,
Storage,
Transaction,
VerkleTree,
Withdrawal,
WithdrawalRequest,
)
Expand Down Expand Up @@ -76,6 +77,7 @@
"TestPrivateKey",
"TestPrivateKey2",
"Transaction",
"VerkleTree",
"Withdrawal",
"WithdrawalRequest",
"ZeroPaddedHexNumber",
Expand Down