Add eth2spec.merge.spec
This commit is contained in:
parent
300832f81a
commit
6e8b4b3ea9
3
Makefile
3
Makefile
|
@ -55,6 +55,7 @@ partial_clean:
|
||||||
rm -rf $(DEPOSIT_CONTRACT_TESTER_DIR)/.pytest_cache
|
rm -rf $(DEPOSIT_CONTRACT_TESTER_DIR)/.pytest_cache
|
||||||
rm -rf $(PY_SPEC_DIR)/phase0
|
rm -rf $(PY_SPEC_DIR)/phase0
|
||||||
rm -rf $(PY_SPEC_DIR)/altair
|
rm -rf $(PY_SPEC_DIR)/altair
|
||||||
|
rm -rf $(PY_SPEC_DIR)/merge
|
||||||
rm -rf $(PY_SPEC_DIR)/$(COV_HTML_OUT)
|
rm -rf $(PY_SPEC_DIR)/$(COV_HTML_OUT)
|
||||||
rm -rf $(PY_SPEC_DIR)/.coverage
|
rm -rf $(PY_SPEC_DIR)/.coverage
|
||||||
rm -rf $(PY_SPEC_DIR)/test-reports
|
rm -rf $(PY_SPEC_DIR)/test-reports
|
||||||
|
@ -119,7 +120,7 @@ codespell:
|
||||||
lint: pyspec
|
lint: pyspec
|
||||||
. venv/bin/activate; cd $(PY_SPEC_DIR); \
|
. venv/bin/activate; cd $(PY_SPEC_DIR); \
|
||||||
flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \
|
flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \
|
||||||
&& mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair
|
&& mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.merge
|
||||||
|
|
||||||
lint_generators: pyspec
|
lint_generators: pyspec
|
||||||
. venv/bin/activate; cd $(TEST_GENERATORS_DIR); \
|
. venv/bin/activate; cd $(TEST_GENERATORS_DIR); \
|
||||||
|
|
94
setup.py
94
setup.py
|
@ -13,7 +13,7 @@ FUNCTION_REGEX = r'^def [\w_]*'
|
||||||
# Definitions in context.py
|
# Definitions in context.py
|
||||||
PHASE0 = 'phase0'
|
PHASE0 = 'phase0'
|
||||||
ALTAIR = 'altair'
|
ALTAIR = 'altair'
|
||||||
|
MERGE = 'merge'
|
||||||
|
|
||||||
class SpecObject(NamedTuple):
|
class SpecObject(NamedTuple):
|
||||||
functions: Dict[str, str]
|
functions: Dict[str, str]
|
||||||
|
@ -99,7 +99,7 @@ def get_spec(file_name: str) -> SpecObject:
|
||||||
ssz_dep_constants[row[0]] = row[1]
|
ssz_dep_constants[row[0]] = row[1]
|
||||||
else:
|
else:
|
||||||
constants[row[0]] = row[1].replace('**TBD**', '2**32')
|
constants[row[0]] = row[1].replace('**TBD**', '2**32')
|
||||||
elif row[1].startswith('uint') or row[1].startswith('Bytes'):
|
elif row[1].startswith('uint') or row[1].startswith('Bytes') or row[1].startswith('ByteList'):
|
||||||
custom_types[row[0]] = row[1]
|
custom_types[row[0]] = row[1]
|
||||||
return SpecObject(
|
return SpecObject(
|
||||||
functions=functions,
|
functions=functions,
|
||||||
|
@ -176,6 +176,34 @@ SSZObject = TypeVar('SSZObject', bound=View)
|
||||||
CONFIG_NAME = 'mainnet'
|
CONFIG_NAME = 'mainnet'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
MERGE_IMPORTS = '''from eth2spec.phase0 import spec as phase0
|
||||||
|
from eth2spec.config.config_util import apply_constants_config
|
||||||
|
from typing import (
|
||||||
|
Any, Callable, Dict, Set, Sequence, Tuple, Optional, TypeVar
|
||||||
|
)
|
||||||
|
|
||||||
|
from dataclasses import (
|
||||||
|
dataclass,
|
||||||
|
field,
|
||||||
|
)
|
||||||
|
|
||||||
|
from lru import LRU
|
||||||
|
|
||||||
|
from eth2spec.utils.ssz.ssz_impl import hash_tree_root, copy, uint_to_bytes
|
||||||
|
from eth2spec.utils.ssz.ssz_typing import (
|
||||||
|
View, boolean, Container, List, Vector, uint8, uint32, uint64, uint256,
|
||||||
|
Bytes1, Bytes4, Bytes20, Bytes32, Bytes48, Bytes96, Bitlist,
|
||||||
|
ByteList, ByteVector
|
||||||
|
)
|
||||||
|
from eth2spec.utils import bls
|
||||||
|
|
||||||
|
from eth2spec.utils.hash_function import hash
|
||||||
|
|
||||||
|
SSZObject = TypeVar('SSZObject', bound=View)
|
||||||
|
|
||||||
|
CONFIG_NAME = 'mainnet'
|
||||||
|
'''
|
||||||
|
|
||||||
SUNDRY_CONSTANTS_FUNCTIONS = '''
|
SUNDRY_CONSTANTS_FUNCTIONS = '''
|
||||||
def ceillog2(x: int) -> uint64:
|
def ceillog2(x: int) -> uint64:
|
||||||
if x < 1:
|
if x < 1:
|
||||||
|
@ -269,6 +297,30 @@ def get_generalized_index(ssz_class: Any, *path: Sequence[Union[int, SSZVariable
|
||||||
return GeneralizedIndex(ssz_path.gindex())'''
|
return GeneralizedIndex(ssz_path.gindex())'''
|
||||||
|
|
||||||
|
|
||||||
|
MERGE_SUNDRY_FUNCTIONS = """
|
||||||
|
ApplicationState = Any
|
||||||
|
|
||||||
|
|
||||||
|
def get_pow_block(hash: Bytes32) -> PowBlock:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_application_state(application_state_root: Bytes32) -> ApplicationState:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_pow_chain_head() -> PowBlock:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def application_state_transition(application_state: ApplicationState, application_payload: ApplicationPayload) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def produce_application_payload(parent_hash: Bytes32) -> ApplicationPayload:
|
||||||
|
pass"""
|
||||||
|
|
||||||
|
|
||||||
# The constants that depend on SSZ objects
|
# The constants that depend on SSZ objects
|
||||||
# Will verify the value at the end of the spec
|
# Will verify the value at the end of the spec
|
||||||
ALTAIR_HARDCODED_SSZ_DEP_CONSTANTS = {
|
ALTAIR_HARDCODED_SSZ_DEP_CONSTANTS = {
|
||||||
|
@ -283,6 +335,11 @@ assert (
|
||||||
) == WEIGHT_DENOMINATOR'''
|
) == WEIGHT_DENOMINATOR'''
|
||||||
|
|
||||||
|
|
||||||
|
MERGE_HARDCODED_CUSTOM_TYPE_DEP_CONSTANTS = {
|
||||||
|
'MAX_BYTES_PER_OPAQUE_TRANSACTION': 'uint64(2**20)',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def is_phase0(fork):
|
def is_phase0(fork):
|
||||||
return fork == PHASE0
|
return fork == PHASE0
|
||||||
|
|
||||||
|
@ -291,6 +348,10 @@ def is_altair(fork):
|
||||||
return fork == ALTAIR
|
return fork == ALTAIR
|
||||||
|
|
||||||
|
|
||||||
|
def is_merge(fork):
|
||||||
|
return fork == MERGE
|
||||||
|
|
||||||
|
|
||||||
def objects_to_spec(spec_object: SpecObject, imports: str, fork: str, ordered_class_objects: Dict[str, str]) -> str:
|
def objects_to_spec(spec_object: SpecObject, imports: str, fork: str, ordered_class_objects: Dict[str, str]) -> str:
|
||||||
"""
|
"""
|
||||||
Given all the objects that constitute a spec, combine them into a single pyfile.
|
Given all the objects that constitute a spec, combine them into a single pyfile.
|
||||||
|
@ -300,6 +361,15 @@ def objects_to_spec(spec_object: SpecObject, imports: str, fork: str, ordered_cl
|
||||||
[
|
[
|
||||||
f"class {key}({value}):\n pass\n"
|
f"class {key}({value}):\n pass\n"
|
||||||
for key, value in spec_object.custom_types.items()
|
for key, value in spec_object.custom_types.items()
|
||||||
|
if not value.startswith('ByteList')
|
||||||
|
]
|
||||||
|
)
|
||||||
|
+ ('\n\n' if len([key for key, value in spec_object.custom_types.items() if value.startswith('ByteList')]) > 0 else '')
|
||||||
|
+ '\n\n'.join(
|
||||||
|
[
|
||||||
|
f"{key} = {value}\n"
|
||||||
|
for key, value in spec_object.custom_types.items()
|
||||||
|
if value.startswith('ByteList')
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -316,9 +386,15 @@ def objects_to_spec(spec_object: SpecObject, imports: str, fork: str, ordered_cl
|
||||||
if is_altair(fork):
|
if is_altair(fork):
|
||||||
altair_ssz_dep_constants = '\n'.join(map(lambda x: '%s = %s' % (x, ALTAIR_HARDCODED_SSZ_DEP_CONSTANTS[x]), ALTAIR_HARDCODED_SSZ_DEP_CONSTANTS))
|
altair_ssz_dep_constants = '\n'.join(map(lambda x: '%s = %s' % (x, ALTAIR_HARDCODED_SSZ_DEP_CONSTANTS[x]), ALTAIR_HARDCODED_SSZ_DEP_CONSTANTS))
|
||||||
|
|
||||||
|
if is_merge(fork):
|
||||||
|
merge_custom_type_dep_constants = '\n'.join(map(lambda x: '%s = %s' % (x, MERGE_HARDCODED_CUSTOM_TYPE_DEP_CONSTANTS[x]), MERGE_HARDCODED_CUSTOM_TYPE_DEP_CONSTANTS))
|
||||||
|
|
||||||
|
|
||||||
spec = (
|
spec = (
|
||||||
imports
|
imports
|
||||||
+ '\n\n' + f"fork = \'{fork}\'\n"
|
+ '\n\n' + f"fork = \'{fork}\'\n"
|
||||||
|
# The constants that some SSZ containers require. Need to be defined before `new_type_definitions`
|
||||||
|
+ ('\n\n' + merge_custom_type_dep_constants + '\n' if is_merge(fork) else '')
|
||||||
+ '\n\n' + new_type_definitions
|
+ '\n\n' + new_type_definitions
|
||||||
+ '\n' + SUNDRY_CONSTANTS_FUNCTIONS
|
+ '\n' + SUNDRY_CONSTANTS_FUNCTIONS
|
||||||
# The constants that some SSZ containers require. Need to be defined before `constants_spec`
|
# The constants that some SSZ containers require. Need to be defined before `constants_spec`
|
||||||
|
@ -330,6 +406,7 @@ def objects_to_spec(spec_object: SpecObject, imports: str, fork: str, ordered_cl
|
||||||
# Functions to make pyspec work
|
# Functions to make pyspec work
|
||||||
+ '\n' + PHASE0_SUNDRY_FUNCTIONS
|
+ '\n' + PHASE0_SUNDRY_FUNCTIONS
|
||||||
+ ('\n' + ALTAIR_SUNDRY_FUNCTIONS if is_altair(fork) else '')
|
+ ('\n' + ALTAIR_SUNDRY_FUNCTIONS if is_altair(fork) else '')
|
||||||
|
+ ('\n' + MERGE_SUNDRY_FUNCTIONS if is_merge(fork) else '')
|
||||||
)
|
)
|
||||||
|
|
||||||
# Since some constants are hardcoded in setup.py, the following assertions verify that the hardcoded constants are
|
# Since some constants are hardcoded in setup.py, the following assertions verify that the hardcoded constants are
|
||||||
|
@ -357,7 +434,7 @@ def combine_constants(old_constants: Dict[str, str], new_constants: Dict[str, st
|
||||||
|
|
||||||
ignored_dependencies = [
|
ignored_dependencies = [
|
||||||
'bit', 'boolean', 'Vector', 'List', 'Container', 'BLSPubkey', 'BLSSignature',
|
'bit', 'boolean', 'Vector', 'List', 'Container', 'BLSPubkey', 'BLSSignature',
|
||||||
'Bytes1', 'Bytes4', 'Bytes32', 'Bytes48', 'Bytes96', 'Bitlist', 'Bitvector',
|
'Bytes1', 'Bytes4', 'Bytes20', 'Bytes32', 'Bytes48', 'Bytes96', 'Bitlist', 'Bitvector',
|
||||||
'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256',
|
'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256',
|
||||||
'bytes', 'byte', 'ByteList', 'ByteVector',
|
'bytes', 'byte', 'ByteList', 'ByteVector',
|
||||||
'Dict', 'dict', 'field', 'ceillog2', 'floorlog2',
|
'Dict', 'dict', 'field', 'ceillog2', 'floorlog2',
|
||||||
|
@ -422,6 +499,7 @@ def combine_spec_objects(spec0: SpecObject, spec1: SpecObject) -> SpecObject:
|
||||||
fork_imports = {
|
fork_imports = {
|
||||||
'phase0': PHASE0_IMPORTS,
|
'phase0': PHASE0_IMPORTS,
|
||||||
'altair': ALTAIR_IMPORTS,
|
'altair': ALTAIR_IMPORTS,
|
||||||
|
'merge': MERGE_IMPORTS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -485,6 +563,16 @@ class PySpecCommand(Command):
|
||||||
specs/altair/validator.md
|
specs/altair/validator.md
|
||||||
specs/altair/sync-protocol.md
|
specs/altair/sync-protocol.md
|
||||||
"""
|
"""
|
||||||
|
elif is_merge(self.spec_fork):
|
||||||
|
self.md_doc_paths = """
|
||||||
|
specs/phase0/beacon-chain.md
|
||||||
|
specs/phase0/fork-choice.md
|
||||||
|
specs/phase0/validator.md
|
||||||
|
specs/phase0/weak-subjectivity.md
|
||||||
|
specs/merge/beacon-chain.md
|
||||||
|
specs/merge/fork-choice.md
|
||||||
|
specs/merge/validator.md
|
||||||
|
"""
|
||||||
else:
|
else:
|
||||||
raise Exception('no markdown files specified, and spec fork "%s" is unknown', self.spec_fork)
|
raise Exception('no markdown files specified, and spec fork "%s" is unknown', self.spec_fork)
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,9 @@ def is_transition_completed(state: BeaconState) -> boolean:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def is_transition_block(state: BeaconState, block_body: BeaconBlockBody) -> boolean:
|
def is_transition_block(state: BeaconState, block_body: BeaconBlockBody) -> boolean:
|
||||||
return state.latest_application_block_header.block_hash == Bytes32() and block_body.application_payload.block_hash != Bytes32()
|
is_empty_latest_application_block_header = state.latest_application_block_header.block_hash == Bytes32()
|
||||||
|
is_empty_application_payload_block_hash = block_body.application_payload.block_hash == Bytes32()
|
||||||
|
return is_empty_latest_application_block_header and not is_empty_application_payload_block_hash
|
||||||
```
|
```
|
||||||
|
|
||||||
### Block processing
|
### Block processing
|
||||||
|
@ -182,14 +184,15 @@ def process_application_payload(state: BeaconState, body: BeaconBlockBody) -> No
|
||||||
"""
|
"""
|
||||||
Note: This function is designed to be able to be run in parallel with the other `process_block` sub-functions
|
Note: This function is designed to be able to be run in parallel with the other `process_block` sub-functions
|
||||||
"""
|
"""
|
||||||
|
application_payload = body.application_payload
|
||||||
|
|
||||||
if not is_transition_completed(state):
|
if not is_transition_completed(state):
|
||||||
assert body.application_payload == ApplicationPayload()
|
assert application_payload == ApplicationPayload()
|
||||||
return
|
return
|
||||||
|
|
||||||
if not is_transition_block(state, body):
|
if not is_transition_block(state, body):
|
||||||
assert body.application_payload.parent_hash == state.latest_application_block_header.block_hash
|
assert application_payload.parent_hash == state.latest_application_block_header.block_hash
|
||||||
assert body.application_payload.number == state.latest_application_block_header.number + 1
|
assert application_payload.number == state.latest_application_block_header.number + 1
|
||||||
|
|
||||||
application_state = get_application_state(state.latest_application_block_header.state_root)
|
application_state = get_application_state(state.latest_application_block_header.state_root)
|
||||||
application_state_transition(application_state, body.application_payload)
|
application_state_transition(application_state, body.application_payload)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import pytest
|
||||||
|
|
||||||
from eth2spec.phase0 import spec as spec_phase0
|
from eth2spec.phase0 import spec as spec_phase0
|
||||||
from eth2spec.altair import spec as spec_altair
|
from eth2spec.altair import spec as spec_altair
|
||||||
|
from eth2spec.merge import spec as spec_merge
|
||||||
from eth2spec.utils import bls
|
from eth2spec.utils import bls
|
||||||
|
|
||||||
from .exceptions import SkippedTest
|
from .exceptions import SkippedTest
|
||||||
|
@ -19,6 +20,7 @@ from importlib import reload
|
||||||
def reload_specs():
|
def reload_specs():
|
||||||
reload(spec_phase0)
|
reload(spec_phase0)
|
||||||
reload(spec_altair)
|
reload(spec_altair)
|
||||||
|
reload(spec_merge)
|
||||||
|
|
||||||
|
|
||||||
# Some of the Spec module functionality is exposed here to deal with phase-specific changes.
|
# Some of the Spec module functionality is exposed here to deal with phase-specific changes.
|
||||||
|
@ -61,9 +63,14 @@ class SpecAltair(Spec):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class SpecMerge(Spec):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
class SpecForks(TypedDict, total=False):
|
class SpecForks(TypedDict, total=False):
|
||||||
PHASE0: SpecPhase0
|
PHASE0: SpecPhase0
|
||||||
ALTAIR: SpecAltair
|
ALTAIR: SpecAltair
|
||||||
|
MERGE: SpecMerge
|
||||||
|
|
||||||
|
|
||||||
def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int],
|
def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int],
|
||||||
|
|
|
@ -6,3 +6,6 @@ from remerkleable.basic import boolean, bit, uint, byte, uint8, uint16, uint32,
|
||||||
from remerkleable.bitfields import Bitvector, Bitlist
|
from remerkleable.bitfields import Bitvector, Bitlist
|
||||||
from remerkleable.byte_arrays import ByteVector, Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, ByteList
|
from remerkleable.byte_arrays import ByteVector, Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, ByteList
|
||||||
from remerkleable.core import BasicView, View, Path
|
from remerkleable.core import BasicView, View, Path
|
||||||
|
|
||||||
|
|
||||||
|
Bytes20 = ByteVector[20] # type: ignore
|
||||||
|
|
Loading…
Reference in New Issue