mirror of
https://github.com/ethereum/consensus-specs.git
synced 2026-02-02 11:55:05 -05:00
@@ -84,11 +84,25 @@ jobs:
|
||||
command: make citest
|
||||
- store_test_results:
|
||||
path: test_libs/pyspec/test-reports
|
||||
lint:
|
||||
docker:
|
||||
- image: circleci/python:3.6
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: v1-specs-repo-{{ .Branch }}-{{ .Revision }}
|
||||
- restore_cached_venv:
|
||||
venv_name: v1-pyspec
|
||||
reqs_checksum: '{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }}'
|
||||
- run:
|
||||
name: Run linter
|
||||
command: make install_lint && make pyspec && make lint
|
||||
workflows:
|
||||
version: 2.1
|
||||
test_spec:
|
||||
jobs:
|
||||
- checkout_specs
|
||||
- lint
|
||||
- install_test:
|
||||
requires:
|
||||
- checkout_specs
|
||||
|
||||
7
Makefile
7
Makefile
@@ -39,6 +39,13 @@ test: $(PY_SPEC_ALL_TARGETS)
|
||||
citest: $(PY_SPEC_ALL_TARGETS)
|
||||
cd $(PY_SPEC_DIR); mkdir -p test-reports/eth2spec; . venv/bin/activate; python -m pytest --junitxml=test-reports/eth2spec/test_results.xml .
|
||||
|
||||
install_lint:
|
||||
cd $(PY_SPEC_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install flake8==3.5.0
|
||||
|
||||
lint:
|
||||
cd $(PY_SPEC_DIR); . venv/bin/activate; \
|
||||
flake8 --max-line-length=120 ./eth2spec;
|
||||
|
||||
# "make pyspec" to create the pyspec for all phases.
|
||||
pyspec: $(PY_SPEC_ALL_TARGETS)
|
||||
|
||||
|
||||
@@ -12,8 +12,18 @@ from typing import (
|
||||
NewType,
|
||||
Tuple,
|
||||
)
|
||||
from eth2spec.utils.minimal_ssz import *
|
||||
from eth2spec.utils.bls_stub import *
|
||||
from eth2spec.utils.minimal_ssz import (
|
||||
SSZType,
|
||||
hash_tree_root,
|
||||
signing_root,
|
||||
)
|
||||
from eth2spec.utils.bls_stub import (
|
||||
bls_aggregate_pubkeys,
|
||||
bls_verify,
|
||||
bls_verify_multiple,
|
||||
)
|
||||
from eth2spec.utils.hash_function import hash
|
||||
|
||||
|
||||
# stub, will get overwritten by real var
|
||||
SLOTS_PER_EPOCH = 64
|
||||
@@ -61,6 +71,7 @@ def hash(x):
|
||||
hash_cache[x] = ret
|
||||
return ret
|
||||
|
||||
|
||||
# Access to overwrite spec constants based on configuration
|
||||
def apply_constants_preset(preset: Dict[str, Any]):
|
||||
global_vars = globals()
|
||||
|
||||
@@ -55,15 +55,19 @@ def get_spec(file_name: str) -> List[str]:
|
||||
if eligible:
|
||||
code_lines.append(row[0] + ' = ' + (row[1].replace('**TBD**', '0x1234567890123456789012345678901234567890')))
|
||||
# Build type-def re-initialization
|
||||
code_lines.append('')
|
||||
code_lines.append('\n')
|
||||
code_lines.append('def init_SSZ_types():')
|
||||
code_lines.append(' global_vars = globals()')
|
||||
for ssz_type_name, ssz_type in type_defs:
|
||||
code_lines.append('')
|
||||
for type_line in ssz_type:
|
||||
code_lines.append(' ' + type_line)
|
||||
if len(type_line) > 0:
|
||||
code_lines.append(' ' + type_line)
|
||||
code_lines.append('\n')
|
||||
code_lines.append('ssz_types = [' + ', '.join([f'\'{ssz_type_name}\'' for (ssz_type_name, _) in type_defs]) + ']')
|
||||
code_lines.append('ssz_types = [\n')
|
||||
for (ssz_type_name, _) in type_defs:
|
||||
code_lines.append(f' {ssz_type_name},\n')
|
||||
code_lines.append(']')
|
||||
code_lines.append('\n')
|
||||
code_lines.append('def get_ssz_type_by_name(name: str) -> SSZType:')
|
||||
code_lines.append(' return globals()[name]')
|
||||
|
||||
@@ -579,8 +579,10 @@ The types are defined topologically to aid in facilitating an executable version
|
||||
'latest_block_roots': ['bytes32', SLOTS_PER_HISTORICAL_ROOT],
|
||||
'latest_state_roots': ['bytes32', SLOTS_PER_HISTORICAL_ROOT],
|
||||
'latest_active_index_roots': ['bytes32', LATEST_ACTIVE_INDEX_ROOTS_LENGTH],
|
||||
'latest_slashed_balances': ['uint64', LATEST_SLASHED_EXIT_LENGTH], # Balances slashed at every withdrawal period
|
||||
'latest_block_header': BeaconBlockHeader, # `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||
# Balances slashed at every withdrawal period
|
||||
'latest_slashed_balances': ['uint64', LATEST_SLASHED_EXIT_LENGTH],
|
||||
# `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||
'latest_block_header': BeaconBlockHeader,
|
||||
'historical_roots': ['bytes32'],
|
||||
|
||||
# Ethereum 1.0 chain data
|
||||
@@ -1149,7 +1151,9 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
||||
#### `slash_validator`
|
||||
|
||||
```python
|
||||
def slash_validator(state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex=None) -> None:
|
||||
def slash_validator(state: BeaconState,
|
||||
slashed_index: ValidatorIndex,
|
||||
whistleblower_index: ValidatorIndex=None) -> None:
|
||||
"""
|
||||
Slash the validator with index ``slashed_index``.
|
||||
"""
|
||||
@@ -1287,7 +1291,8 @@ def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> List[Pen
|
||||
```
|
||||
|
||||
```python
|
||||
def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]:
|
||||
def get_unslashed_attesting_indices(state: BeaconState,
|
||||
attestations: List[PendingAttestation]) -> List[ValidatorIndex]:
|
||||
output = set()
|
||||
for a in attestations:
|
||||
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield))
|
||||
@@ -1300,7 +1305,9 @@ def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestat
|
||||
```
|
||||
|
||||
```python
|
||||
def get_winning_crosslink_and_attesting_indices(state: BeaconState, epoch: Epoch, shard: Shard) -> Tuple[Crosslink, List[ValidatorIndex]]:
|
||||
def get_winning_crosslink_and_attesting_indices(state: BeaconState,
|
||||
epoch: Epoch,
|
||||
shard: Shard) -> Tuple[Crosslink, List[ValidatorIndex]]:
|
||||
attestations = [a for a in get_matching_source_attestations(state, epoch) if a.data.crosslink.shard == shard]
|
||||
crosslinks = list(filter(
|
||||
lambda c: hash_tree_root(state.current_crosslinks[shard]) in (c.parent_root, hash_tree_root(c)),
|
||||
@@ -1332,12 +1339,16 @@ def process_justification_and_finalization(state: BeaconState) -> None:
|
||||
state.previous_justified_epoch = state.current_justified_epoch
|
||||
state.previous_justified_root = state.current_justified_root
|
||||
state.justification_bitfield = (state.justification_bitfield << 1) % 2**64
|
||||
previous_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, previous_epoch))
|
||||
previous_epoch_matching_target_balance = get_attesting_balance(
|
||||
state, get_matching_target_attestations(state, previous_epoch)
|
||||
)
|
||||
if previous_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2:
|
||||
state.current_justified_epoch = previous_epoch
|
||||
state.current_justified_root = get_block_root(state, state.current_justified_epoch)
|
||||
state.justification_bitfield |= (1 << 1)
|
||||
current_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, current_epoch))
|
||||
current_epoch_matching_target_balance = get_attesting_balance(
|
||||
state, get_matching_target_attestations(state, current_epoch)
|
||||
)
|
||||
if current_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2:
|
||||
state.current_justified_epoch = current_epoch
|
||||
state.current_justified_root = get_block_root(state, state.current_justified_epoch)
|
||||
@@ -1431,7 +1442,9 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
||||
for index in eligible_validator_indices:
|
||||
penalties[index] += BASE_REWARDS_PER_EPOCH * get_base_reward(state, index)
|
||||
if index not in matching_target_attesting_indices:
|
||||
penalties[index] += state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
|
||||
penalties[index] += (
|
||||
state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
|
||||
)
|
||||
|
||||
return rewards, penalties
|
||||
```
|
||||
@@ -1478,7 +1491,10 @@ Run the following function:
|
||||
def process_registry_updates(state: BeaconState) -> None:
|
||||
# Process activation eligibility and ejections
|
||||
for index, validator in enumerate(state.validator_registry):
|
||||
if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
|
||||
if (
|
||||
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
|
||||
validator.effective_balance >= MAX_EFFECTIVE_BALANCE
|
||||
):
|
||||
validator.activation_eligibility_epoch = get_current_epoch(state)
|
||||
|
||||
if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE:
|
||||
@@ -1603,7 +1619,12 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
||||
def process_randao(state: BeaconState, block: BeaconBlock) -> None:
|
||||
proposer = state.validator_registry[get_beacon_proposer_index(state)]
|
||||
# Verify that the provided randao value is valid
|
||||
assert bls_verify(proposer.pubkey, hash_tree_root(get_current_epoch(state)), block.body.randao_reveal, get_domain(state, DOMAIN_RANDAO))
|
||||
assert bls_verify(
|
||||
proposer.pubkey,
|
||||
hash_tree_root(get_current_epoch(state)),
|
||||
block.body.randao_reveal,
|
||||
get_domain(state, DOMAIN_RANDAO),
|
||||
)
|
||||
# Mix it in
|
||||
state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = (
|
||||
xor(get_randao_mix(state, get_current_epoch(state)),
|
||||
@@ -1748,7 +1769,9 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||
validator_pubkeys = [v.pubkey for v in state.validator_registry]
|
||||
if pubkey not in validator_pubkeys:
|
||||
# Verify the deposit signature (proof of possession)
|
||||
if not bls_verify(pubkey, signing_root(deposit.data), deposit.data.signature, get_domain(state, DOMAIN_DEPOSIT)):
|
||||
if not bls_verify(
|
||||
pubkey, signing_root(deposit.data), deposit.data.signature, get_domain(state, DOMAIN_DEPOSIT)
|
||||
):
|
||||
return
|
||||
|
||||
# Add validator and balance entries
|
||||
|
||||
@@ -16,11 +16,11 @@ def decode(json, typ):
|
||||
for field, subtype in typ.fields.items():
|
||||
temp[field] = decode(json[field], subtype)
|
||||
if field + "_hash_tree_root" in json:
|
||||
assert(json[field + "_hash_tree_root"][2:] ==
|
||||
assert(json[field + "_hash_tree_root"][2:] ==
|
||||
hash_tree_root(temp[field], subtype).hex())
|
||||
ret = typ(**temp)
|
||||
if "hash_tree_root" in json:
|
||||
assert(json["hash_tree_root"][2:] ==
|
||||
assert(json["hash_tree_root"][2:] ==
|
||||
hash_tree_root(ret, typ).hex())
|
||||
return ret
|
||||
else:
|
||||
|
||||
@@ -25,4 +25,3 @@ def encode(value, typ, include_hash_tree_roots=False):
|
||||
else:
|
||||
print(value, typ)
|
||||
raise Exception("Type not recognized")
|
||||
|
||||
|
||||
@@ -31,7 +31,12 @@ class RandomizationMode(Enum):
|
||||
return self.value in [0, 4, 5]
|
||||
|
||||
|
||||
def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list_length: int, mode: RandomizationMode, chaos: bool) -> Any:
|
||||
def get_random_ssz_object(rng: Random,
|
||||
typ: Any,
|
||||
max_bytes_length: int,
|
||||
max_list_length: int,
|
||||
mode: RandomizationMode,
|
||||
chaos: bool) -> Any:
|
||||
"""
|
||||
Create an object for a given type, filled with random data.
|
||||
:param rng: The random number generator to use.
|
||||
@@ -77,7 +82,10 @@ def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list
|
||||
return get_random_basic_value(rng, typ)
|
||||
# Vector:
|
||||
elif isinstance(typ, list) and len(typ) == 2:
|
||||
return [get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos) for _ in range(typ[1])]
|
||||
return [
|
||||
get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos)
|
||||
for _ in range(typ[1])
|
||||
]
|
||||
# List:
|
||||
elif isinstance(typ, list) and len(typ) == 1:
|
||||
length = rng.randint(0, max_list_length)
|
||||
@@ -85,10 +93,17 @@ def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list
|
||||
length = 1
|
||||
if mode == RandomizationMode.mode_max_count:
|
||||
length = max_list_length
|
||||
return [get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos) for _ in range(length)]
|
||||
return [
|
||||
get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos)
|
||||
for _ in range(length)
|
||||
]
|
||||
# Container:
|
||||
elif hasattr(typ, 'fields'):
|
||||
return typ(**{field: get_random_ssz_object(rng, subtype, max_bytes_length, max_list_length, mode, chaos) for field, subtype in typ.fields.items()})
|
||||
return typ(**{
|
||||
field:
|
||||
get_random_ssz_object(rng, subtype, max_bytes_length, max_list_length, mode, chaos)
|
||||
for field, subtype in typ.fields.items()
|
||||
})
|
||||
else:
|
||||
print(typ)
|
||||
raise Exception("Type not recognized")
|
||||
|
||||
Reference in New Issue
Block a user