Skip to content

Commit

Permalink
forks: Fix default values on getters
Browse files Browse the repository at this point in the history
Co-authored-by: danceratopz <danceratopz@gmail.com>
  • Loading branch information
marioevz and danceratopz committed Jul 25, 2023
1 parent f23b5be commit 75fd088
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 61 deletions.
22 changes: 12 additions & 10 deletions src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class BaseFork(ABC, metaclass=BaseForkMeta):

@classmethod
@abstractmethod
def fork(cls, block_number: int, timestamp: int) -> str:
def fork(cls, block_number: int = 0, timestamp: int = 0) -> str:
"""
Returns fork name as it's meant to be passed to the transition tool for execution.
"""
Expand All @@ -41,55 +41,55 @@ def fork(cls, block_number: int, timestamp: int) -> str:
# Header information abstract methods
@classmethod
@abstractmethod
def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:
def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the header must contain base fee
"""
pass

@classmethod
@abstractmethod
def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:
def header_prev_randao_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the header must contain Prev Randao value
"""
pass

@classmethod
@abstractmethod
def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:
def header_zero_difficulty_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the header must have difficulty zero
"""
pass

@classmethod
@abstractmethod
def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:
def header_withdrawals_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the header must contain withdrawals
"""
pass

@classmethod
@abstractmethod
def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:
def header_excess_data_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the header must contain excess data gas
"""
pass

@classmethod
@abstractmethod
def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:
def header_data_gas_used_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the header must contain data gas used
"""
pass

@classmethod
@abstractmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
Returns the expected reward amount in wei of a given fork
"""
Expand All @@ -98,7 +98,9 @@ def get_reward(cls, block_number: int, timestamp: int) -> int:
# Engine API information abstract methods
@classmethod
@abstractmethod
def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:
def engine_new_payload_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
Returns `None` if this fork's payloads cannot be sent over the engine API,
or the payload version if it can.
Expand All @@ -107,7 +109,7 @@ def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Option

@classmethod
@abstractmethod
def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Returns true if the engine api version requires new payload calls to include blob hashes.
"""
Expand Down
54 changes: 31 additions & 23 deletions src/ethereum_test_forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,70 +13,72 @@ class Frontier(BaseFork):
"""

@classmethod
def fork(cls, block_number: int, timestamp: int) -> str:
def fork(cls, block_number: int = 0, timestamp: int = 0) -> str:
"""
Returns fork name as it's meant to be passed to the transition tool for execution.
"""
return cls.name()

@classmethod
def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:
def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, header must not contain base fee
"""
return False

@classmethod
def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:
def header_prev_randao_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, header must not contain Prev Randao value
"""
return False

@classmethod
def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:
def header_zero_difficulty_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, header must not have difficulty zero
"""
return False

@classmethod
def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:
def header_withdrawals_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, header must not contain withdrawals
"""
return False

@classmethod
def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:
def header_excess_data_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, header must not contain excess data gas
"""
return False

@classmethod
def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:
def header_data_gas_used_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, header must not contain data gas used
"""
return False

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

@classmethod
def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
At genesis, payloads do not have blob hashes.
"""
return False

@classmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
At Genesis the expected reward amount in wei is
5_000_000_000_000_000_000
Expand All @@ -98,7 +100,7 @@ class Byzantium(Homestead):
"""

@classmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
At Byzantium, the block reward is reduced to
3_000_000_000_000_000_000 wei
Expand All @@ -112,7 +114,7 @@ class Constantinople(Byzantium):
"""

@classmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
At Constantinople, the block reward is reduced to
2_000_000_000_000_000_000 wei
Expand Down Expand Up @@ -159,7 +161,7 @@ class London(Berlin):
"""

@classmethod
def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:
def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Base Fee is required starting from London.
"""
Expand Down Expand Up @@ -189,28 +191,30 @@ class Merge(London):
"""

@classmethod
def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:
def header_prev_randao_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Prev Randao is required starting from Merge.
"""
return True

@classmethod
def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:
def header_zero_difficulty_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Zero difficulty is required starting from Merge.
"""
return True

@classmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
Merge updates the reward to 0.
"""
return 0

@classmethod
def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:
def engine_new_payload_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
Starting at the merge, payloads can be sent through the engine API
"""
Expand All @@ -223,14 +227,16 @@ class Shanghai(Merge):
"""

@classmethod
def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:
def header_withdrawals_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Withdrawals are required starting from Shanghai.
"""
return True

@classmethod
def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:
def engine_new_payload_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
Starting at Shanghai, new payload calls must use version 2
"""
Expand All @@ -251,28 +257,30 @@ def is_deployed(cls):
return False

@classmethod
def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:
def header_excess_data_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Excess data gas is required starting from Cancun.
"""
return True

@classmethod
def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:
def header_data_gas_used_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Data gas used is required starting from Cancun.
"""
return True

@classmethod
def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:
def engine_new_payload_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
Starting at Cancun, new payload calls must use version 3
"""
return 3

@classmethod
def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
"""
Starting at Cancun, payloads must have blob hashes.
"""
Expand Down
6 changes: 6 additions & 0 deletions src/ethereum_test_forks/tests/test_forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ def test_transition_forks():

assert BerlinToLondonAt5.fork(4, 0) == "Berlin"
assert BerlinToLondonAt5.fork(5, 0) == "London"
# Default values of transition forks is the transition block
assert BerlinToLondonAt5.fork() == "London"

assert MergeToShanghaiAtTime15k.fork(0, 14_999) == "Merge"
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
Expand Down Expand Up @@ -80,12 +83,15 @@ def test_forks():
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
# Default values of normal forks if the genesis block
assert Merge.header_base_fee_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, 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

assert is_fork(Berlin, Berlin) is True
assert is_fork(London, Berlin) is True
Expand Down
26 changes: 20 additions & 6 deletions src/ethereum_test_forks/transition_base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

from .base_fork import BaseFork, Fork

ALWAYS_TRANSITIONED_BLOCK_NUMBER = 10_000
ALWAYS_TRANSITIONED_BLOCK_TIMESTAMP = 10_000_000


class TransitionBaseClass:
"""
Expand Down Expand Up @@ -48,17 +51,28 @@ class NewTransitionClass(cls, TransitionBaseClass, BaseFork): # type: ignore

NewTransitionClass.name = lambda: transition_name # type: ignore

for method_name in base_fork_abstract_methods():
def make_transition_method(from_fork_method, to_fork_method):
def transition_method(
cls,
block_number: int = ALWAYS_TRANSITIONED_BLOCK_NUMBER,
timestamp: int = ALWAYS_TRANSITIONED_BLOCK_TIMESTAMP,
):
return (
to_fork_method(block_number, timestamp)
if block_number >= at_block and timestamp >= at_timestamp
else from_fork_method(block_number, timestamp)
)

def _method(cls, block_number: int, timestamp: int, method_name=method_name):
if block_number >= at_block and timestamp >= at_timestamp:
return getattr(to_fork, method_name)(block_number, timestamp)
return getattr(from_fork, method_name)(block_number, timestamp)
return classmethod(transition_method)

for method_name in base_fork_abstract_methods():
setattr(
NewTransitionClass,
method_name,
classmethod(_method),
make_transition_method(
getattr(from_fork, method_name),
getattr(to_fork, method_name),
),
)

NewTransitionClass.transitions_to = lambda: to_fork # type: ignore
Expand Down
11 changes: 2 additions & 9 deletions src/evm_transition_tool/besu.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@

from ethereum_test_forks import Fork

from .transition_tool import (
ALWAYS_TRANSITIONED_BLOCK_NUMBER,
ALWAYS_TRANSITIONED_BLOCK_TIMESTAMP,
TransitionTool,
)
from .transition_tool import TransitionTool


class BesuTransitionTool(TransitionTool):
Expand Down Expand Up @@ -147,7 +143,4 @@ def is_fork_supported(self, fork: Fork) -> bool:
"""
Returns True if the fork is supported by the tool
"""
return (
fork.fork(ALWAYS_TRANSITIONED_BLOCK_NUMBER, ALWAYS_TRANSITIONED_BLOCK_TIMESTAMP)
in self.help_string
)
return fork.fork() in self.help_string
Loading

0 comments on commit 75fd088

Please sign in to comment.