From 9fc197af672fd2a237d80efa987f5e840341091f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 10 Jun 2019 11:10:13 -0400 Subject: [PATCH 01/21] class Bytes32 --- scripts/build_spec.py | 7 ++++--- .../pyspec/eth2spec/utils/ssz/ssz_typing.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 7a51970e38..087a88f983 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -25,7 +25,8 @@ ) from eth2spec.utils.ssz.ssz_typing import ( # unused: uint8, uint16, uint32, uint128, uint256, - uint64, Container, Vector, BytesN + uint64, Container, Vector, + Bytes4, Bytes32, Bytes48, Bytes96, ) from eth2spec.utils.bls import ( bls_aggregate_pubkeys, @@ -52,7 +53,8 @@ ) from eth2spec.utils.ssz.ssz_typing import ( # unused: uint8, uint16, uint32, uint128, uint256, - uint64, Container, Vector, BytesN + uint64, Container, Vector, + Bytes4, Bytes32, Bytes48, Bytes96, ) from eth2spec.utils.bls import ( bls_aggregate_pubkeys, @@ -132,7 +134,6 @@ def objects_to_spec(functions: Dict[str, str], """ new_type_definitions = \ '\n'.join(['''%s = NewType('%s', %s)''' % (key, key, value) for key, value in new_types.items()]) - new_type_definitions += '\n' + '\n'.join(['Bytes%s = BytesN[%s]' % (n, n) for n in byte_types]) functions_spec = '\n\n'.join(functions.values()) constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants)) ssz_objects_instantiation_spec = '\n\n'.join(ssz_objects.values()) diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 368041f90a..e40c904cad 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -390,6 +390,22 @@ def hash_tree_root(self): return hash_tree_root(self, self.__class__) +class Bytes4(BytesN): + length = 4 + + +class Bytes32(BytesN): + length = 32 + + +class Bytes48(BytesN): + length = 48 + + +class Bytes96(BytesN): + length = 96 + + # SSZ Defaults # ----------------------------- def get_zero_value(typ): From 8b64f37d225bf0d5971735bd8088418dd68b096c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 10 Jun 2019 23:16:59 -0400 Subject: [PATCH 02/21] Make uint64 be `class` for type hinting --- scripts/build_spec.py | 36 +++++++++++-------- .../pyspec/eth2spec/utils/ssz/ssz_typing.py | 21 ++++++----- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 087a88f983..0ede5f1d98 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -15,7 +15,6 @@ Any, Dict, List, - NewType, Tuple, ) @@ -41,7 +40,6 @@ Any, Dict, List, - NewType, Tuple, ) @@ -65,11 +63,11 @@ from eth2spec.utils.hash_function import hash ''' NEW_TYPES = { - 'Slot': 'int', - 'Epoch': 'int', - 'Shard': 'int', - 'ValidatorIndex': 'int', - 'Gwei': 'int', + 'Slot': 'uint64', + 'Epoch': 'uint64', + 'Shard': 'uint64', + 'ValidatorIndex': 'uint64', + 'Gwei': 'uint64', } BYTE_TYPES = [4, 32, 48, 96] SUNDRY_FUNCTIONS = ''' @@ -79,7 +77,7 @@ def get_ssz_type_by_name(name: str) -> Container: # Monkey patch validator compute committee code _compute_committee = compute_committee -committee_cache = {} +committee_cache = {} # type: Dict[Tuple[Bytes32, Bytes32, ValidatorIndex, int], List[ValidatorIndex]] def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, count: int) -> List[ValidatorIndex]: @@ -95,10 +93,10 @@ def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, # Monkey patch hash cache _hash = hash -hash_cache = {} +hash_cache: Dict[bytes, Bytes32] = {} -def hash(x): +def hash(x: bytes) -> Bytes32: if x in hash_cache: return hash_cache[x] else: @@ -108,7 +106,7 @@ def hash(x): # Access to overwrite spec constants based on configuration -def apply_constants_preset(preset: Dict[str, Any]): +def apply_constants_preset(preset: Dict[str, Any]) -> None: global_vars = globals() for k, v in preset.items(): global_vars[k] = v @@ -132,20 +130,28 @@ def objects_to_spec(functions: Dict[str, str], """ Given all the objects that constitute a spec, combine them into a single pyfile. """ - new_type_definitions = \ - '\n'.join(['''%s = NewType('%s', %s)''' % (key, key, value) for key, value in new_types.items()]) + new_type_definitions = ( + '\n\n'.join( + [ + f"class {key}({value}):\n" + f" def __init__(self, _x: uint64) -> None:\n" + f" ...\n" + for key, value in new_types.items() + ] + ) + ) functions_spec = '\n\n'.join(functions.values()) constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants)) ssz_objects_instantiation_spec = '\n\n'.join(ssz_objects.values()) ssz_objects_reinitialization_spec = ( - 'def init_SSZ_types():\n global_vars = globals()\n\n ' + 'def init_SSZ_types() -> None:\n global_vars = globals()\n\n ' + '\n\n '.join([re.sub(r'(?!\n\n)\n', r'\n ', value[:-1]) for value in ssz_objects.values()]) + '\n\n' + '\n'.join(map(lambda x: ' global_vars[\'%s\'] = %s' % (x, x), ssz_objects.keys())) ) spec = ( imports - + '\n' + new_type_definitions + + '\n\n' + new_type_definitions + '\n\n' + constants_spec + '\n\n\n' + ssz_objects_instantiation_spec + '\n\n' + functions_spec diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index e40c904cad..cde1586c14 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -46,8 +46,13 @@ def __new__(cls, value, *args, **kwargs): return super().__new__(cls, value) -# We simply default to uint64. But do give it a name, for readability -uint64 = NewType('uint64', int) +class uint64(uint): + byte_len = 8 + + def __new__(cls, value, *args, **kwargs): + if value.bit_length() > 64: + raise ValueError("value out of bounds for uint128") + return super().__new__(cls, value) class uint128(uint): @@ -409,12 +414,12 @@ class Bytes96(BytesN): # SSZ Defaults # ----------------------------- def get_zero_value(typ): - if is_uint_type(typ): - return 0 - elif is_list_type(typ): + if is_list_type(typ): return [] elif is_bool_type(typ): return False + elif is_uint_type(typ): + return uint64(0) elif is_vector_type(typ): return typ() elif is_bytesn_type(typ): @@ -432,12 +437,12 @@ def get_zero_value(typ): def infer_type(obj): - if is_uint_type(obj.__class__): - return obj.__class__ - elif isinstance(obj, int): + if isinstance(obj, int): return uint64 elif isinstance(obj, list): return List[infer_type(obj[0])] + elif is_uint_type(obj.__class__): + return obj.__class__ elif isinstance(obj, (Vector, Container, bool, BytesN, bytes)): return obj.__class__ else: From 9f454185f8448772a9cea4bc19a71f7b3808c7f2 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 11 Jun 2019 00:15:52 -0400 Subject: [PATCH 03/21] WIP! 1. Use custom types in SSZ declaration 2. Casting --- scripts/build_spec.py | 9 +- specs/core/0_beacon-chain.md | 172 +++++++++--------- .../pyspec/eth2spec/utils/ssz/ssz_typing.py | 2 +- 3 files changed, 95 insertions(+), 88 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 0ede5f1d98..f396d3b9c5 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -15,6 +15,7 @@ Any, Dict, List, + Set, Tuple, ) @@ -40,6 +41,7 @@ Any, Dict, List, + Set, Tuple, ) @@ -77,10 +79,13 @@ def get_ssz_type_by_name(name: str) -> Container: # Monkey patch validator compute committee code _compute_committee = compute_committee -committee_cache = {} # type: Dict[Tuple[Bytes32, Bytes32, ValidatorIndex, int], List[ValidatorIndex]] +committee_cache: Dict[Tuple[Bytes32, Bytes32, int, int], List[ValidatorIndex]] = {} -def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, count: int) -> List[ValidatorIndex]: +def compute_committee(indices: List[ValidatorIndex], # type: ignore + seed: Bytes32, + index: int, + count: int) -> List[ValidatorIndex]: param_hash = (hash_tree_root(indices), seed, index, count) if param_hash in committee_cache: diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a6d9d23c58..a6bfd5e1ac 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -180,18 +180,18 @@ These configurations are updated for releases, but may be out of sync during `de | Name | Value | Unit | | - | - | :-: | -| `MIN_DEPOSIT_AMOUNT` | `2**0 * 10**9` (= 1,000,000,000) | Gwei | -| `MAX_EFFECTIVE_BALANCE` | `2**5 * 10**9` (= 32,000,000,000) | Gwei | -| `EJECTION_BALANCE` | `2**4 * 10**9` (= 16,000,000,000) | Gwei | -| `EFFECTIVE_BALANCE_INCREMENT` | `2**0 * 10**9` (= 1,000,000,000) | Gwei | +| `MIN_DEPOSIT_AMOUNT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | Gwei | +| `MAX_EFFECTIVE_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | Gwei | +| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) | Gwei | +| `EFFECTIVE_BALANCE_INCREMENT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | Gwei | ### Initial values | Name | Value | | - | - | -| `GENESIS_SLOT` | `0` | -| `GENESIS_EPOCH` | `0` | -| `FAR_FUTURE_EPOCH` | `2**64 - 1` | +| `GENESIS_SLOT` | `Slot(0)` | +| `GENESIS_EPOCH` | `Epoch(0)` | +| `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` | | `ZERO_HASH` | `b'\x00' * 32` | | `BLS_WITHDRAWAL_PREFIX` | `0` | @@ -272,7 +272,7 @@ class Fork(Container): # Current fork version current_version: Bytes4 # Fork epoch number - epoch: uint64 + epoch: Epoch ``` #### `Validator` @@ -284,17 +284,17 @@ class Validator(Container): # Withdrawal credentials withdrawal_credentials: Bytes32 # Epoch when became eligible for activation - activation_eligibility_epoch: uint64 + activation_eligibility_epoch: Epoch # Epoch when validator activated - activation_epoch: uint64 + activation_epoch: Epoch # Epoch when validator exited - exit_epoch: uint64 + exit_epoch: Epoch # Epoch when validator is eligible to withdraw - withdrawable_epoch: uint64 + withdrawable_epoch: Epoch # Was the validator slashed slashed: bool # Effective balance - effective_balance: uint64 + effective_balance: Gwei ``` #### `Crosslink` @@ -302,10 +302,10 @@ class Validator(Container): ```python class Crosslink(Container): # Shard number - shard: uint64 + shard: Shard # Crosslinking data from epochs [start....end-1] - start_epoch: uint64 - end_epoch: uint64 + start_epoch: Epoch + end_epoch: Epoch # Root of the previous crosslink parent_root: Bytes32 # Root of the crosslinked shard data since the previous crosslink @@ -320,9 +320,9 @@ class AttestationData(Container): beacon_block_root: Bytes32 # FFG vote - source_epoch: uint64 + source_epoch: Epoch source_root: Bytes32 - target_epoch: uint64 + target_epoch: Epoch target_root: Bytes32 # Crosslink vote @@ -344,8 +344,8 @@ class AttestationDataAndCustodyBit(Container): ```python class IndexedAttestation(Container): # Validator indices - custody_bit_0_indices: List[uint64] - custody_bit_1_indices: List[uint64] + custody_bit_0_indices: List[ValidatorIndex] + custody_bit_1_indices: List[ValidatorIndex] # Attestation data data: AttestationData # Aggregate signature @@ -363,7 +363,7 @@ class PendingAttestation(Container): # Inclusion delay inclusion_delay: uint64 # Proposer index - proposer_index: uint64 + proposer_index: ValidatorIndex ``` #### `Eth1Data` @@ -397,7 +397,7 @@ class DepositData(Container): # Withdrawal credentials withdrawal_credentials: Bytes32 # Amount in Gwei - amount: uint64 + amount: Gwei # Container self-signature signature: Bytes96 ``` @@ -406,7 +406,7 @@ class DepositData(Container): ```python class BeaconBlockHeader(Container): - slot: uint64 + slot: Slot parent_root: Bytes32 state_root: Bytes32 body_root: Bytes32 @@ -420,7 +420,7 @@ class BeaconBlockHeader(Container): ```python class ProposerSlashing(Container): # Proposer index - proposer_index: uint64 + proposer_index: ValidatorIndex # First block header header_1: BeaconBlockHeader # Second block header @@ -466,9 +466,9 @@ class Deposit(Container): ```python class VoluntaryExit(Container): # Minimum epoch for processing exit - epoch: uint64 + epoch: Epoch # Index of the exiting validator - validator_index: uint64 + validator_index: ValidatorIndex # Validator signature signature: Bytes96 ``` @@ -478,15 +478,15 @@ class VoluntaryExit(Container): ```python class Transfer(Container): # Sender index - sender: uint64 + sender: ValidatorIndex # Recipient index - recipient: uint64 + recipient: ValidatorIndex # Amount in Gwei - amount: uint64 + amount: Gwei # Fee in Gwei for block proposer - fee: uint64 + fee: Gwei # Inclusion slot - slot: uint64 + slot: Slot # Sender withdrawal pubkey pubkey: Bytes48 # Sender signature @@ -515,7 +515,7 @@ class BeaconBlockBody(Container): ```python class BeaconBlock(Container): # Header - slot: uint64 + slot: Slot parent_root: Bytes32 state_root: Bytes32 body: BeaconBlockBody @@ -529,24 +529,24 @@ class BeaconBlock(Container): ```python class BeaconState(Container): # Misc - slot: uint64 + slot: Slot genesis_time: uint64 fork: Fork # For versioning hard forks # Validator registry validator_registry: List[Validator] - balances: List[uint64] + balances: List[Gwei] # Randomness and committees latest_randao_mixes: Vector[Bytes32, LATEST_RANDAO_MIXES_LENGTH] - latest_start_shard: uint64 + latest_start_shard: Shard # Finality previous_epoch_attestations: List[PendingAttestation] current_epoch_attestations: List[PendingAttestation] - previous_justified_epoch: uint64 - current_justified_epoch: uint64 + previous_justified_epoch: Epoch + current_justified_epoch: Epoch previous_justified_root: Bytes32 current_justified_root: Bytes32 justification_bitfield: uint64 - finalized_epoch: uint64 + finalized_epoch: Epoch finalized_root: Bytes32 # Recent state current_crosslinks: Vector[Crosslink, SHARD_COUNT] @@ -554,7 +554,7 @@ class BeaconState(Container): latest_block_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] latest_state_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] latest_active_index_roots: Vector[Bytes32, LATEST_ACTIVE_INDEX_ROOTS_LENGTH] - latest_slashed_balances: Vector[uint64, LATEST_SLASHED_EXIT_LENGTH] + latest_slashed_balances: Vector[Gwei, LATEST_SLASHED_EXIT_LENGTH] latest_block_header: BeaconBlockHeader historical_roots: List[Bytes32] # Ethereum 1.0 chain data @@ -619,7 +619,7 @@ def slot_to_epoch(slot: Slot) -> Epoch: """ Return the epoch number of the given ``slot``. """ - return slot // SLOTS_PER_EPOCH + return Epoch(slot // SLOTS_PER_EPOCH) ``` ### `get_previous_epoch` @@ -631,7 +631,7 @@ def get_previous_epoch(state: BeaconState) -> Epoch: Return the current epoch if it's genesis epoch. """ current_epoch = get_current_epoch(state) - return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else current_epoch - 1 + return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1) ``` ### `get_current_epoch` @@ -651,7 +651,7 @@ def get_epoch_start_slot(epoch: Epoch) -> Slot: """ Return the starting slot of the given ``epoch``. """ - return epoch * SLOTS_PER_EPOCH + return Slot(epoch * SLOTS_PER_EPOCH) ``` ### `is_active_validator` @@ -681,7 +681,7 @@ def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> List[Valid """ Get active validator indices at ``epoch``. """ - return [i for i, v in enumerate(state.validator_registry) if is_active_validator(v, epoch)] + return [ValidatorIndex(i) for i, v in enumerate(state.validator_registry) if is_active_validator(v, epoch)] ``` ### `increase_balance` @@ -737,10 +737,10 @@ def get_shard_delta(state: BeaconState, epoch: Epoch) -> int: def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard: assert epoch <= get_current_epoch(state) + 1 check_epoch = get_current_epoch(state) + 1 - shard = (state.latest_start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT + shard = Shard((state.latest_start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT) while check_epoch > epoch: check_epoch -= 1 - shard = (shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT + shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, Epoch(check_epoch))) % SHARD_COUNT) return shard ``` @@ -750,7 +750,7 @@ def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard: def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot: committee_count = get_epoch_committee_count(state, data.target_epoch) offset = (data.crosslink.shard + SHARD_COUNT - get_epoch_start_shard(state, data.target_epoch)) % SHARD_COUNT - return get_epoch_start_slot(data.target_epoch) + offset // (committee_count // SLOTS_PER_EPOCH) + return Slot(get_epoch_start_slot(data.target_epoch) + offset // (committee_count // SLOTS_PER_EPOCH)) ``` ### `get_block_root_at_slot` @@ -810,7 +810,7 @@ def generate_seed(state: BeaconState, Generate a seed for the given ``epoch``. """ return hash( - get_randao_mix(state, epoch + LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD) + + get_randao_mix(state, Epoch(epoch + LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD)) + get_active_index_root(state, epoch) + int_to_bytes(epoch, length=32) ) @@ -826,7 +826,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: epoch = get_current_epoch(state) committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH) - shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT + shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT) first_committee = get_crosslink_committee(state, epoch, shard) MAX_RANDOM_BYTE = 2**8 - 1 seed = generate_seed(state, epoch) @@ -836,7 +836,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32] effective_balance = state.validator_registry[candidate_index].effective_balance if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: - return candidate_index + return ValidatorIndex(candidate_index) i += 1 ``` @@ -860,7 +860,7 @@ def verify_merkle_branch(leaf: Bytes32, proof: List[Bytes32], depth: int, index: ### `get_shuffled_index` ```python -def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Bytes32) -> ValidatorIndex: +def get_shuffled_index(index: int, index_count: int, seed: Bytes32) -> ValidatorIndex: """ Return the shuffled validator index corresponding to ``seed`` (and ``index_count``). """ @@ -869,16 +869,16 @@ def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Bytes32) - # Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf) # See the 'generalized domain' algorithm on page 3 - for round in range(SHUFFLE_ROUND_COUNT): - pivot = bytes_to_int(hash(seed + int_to_bytes(round, length=1))[0:8]) % index_count + for current_round in range(SHUFFLE_ROUND_COUNT): + pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count flip = (pivot + index_count - index) % index_count position = max(index, flip) - source = hash(seed + int_to_bytes(round, length=1) + int_to_bytes(position // 256, length=4)) + source = hash(seed + int_to_bytes(current_round, length=1) + int_to_bytes(position // 256, length=4)) byte = source[(position % 256) // 8] bit = (byte >> (position % 8)) % 2 index = flip if bit else index - return index + return ValidatorIndex(index) ``` ### `compute_committee` @@ -887,7 +887,7 @@ def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Bytes32) - def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, count: int) -> List[ValidatorIndex]: start = (len(indices) * index) // count end = (len(indices) * (index + 1)) // count - return [indices[get_shuffled_index(i, len(indices), seed)] for i in range(start, end)] + return [indices[get_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)] ``` ### `get_crosslink_committee` @@ -937,7 +937,7 @@ def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei """ Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.) """ - return max(sum([state.validator_registry[index].effective_balance for index in indices]), 1) + return Gwei(max(sum([state.validator_registry[index].effective_balance for index in indices]), 1)) ``` ### `get_domain` @@ -945,7 +945,7 @@ def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei ```python def get_domain(state: BeaconState, domain_type: int, - message_epoch: int=None) -> int: + message_epoch: Epoch=None) -> int: """ Return the signature domain (fork version concatenated with domain type) of a message. """ @@ -1072,7 +1072,7 @@ def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch: """ Return the epoch at which an activation or exit triggered in ``epoch`` takes effect. """ - return epoch + 1 + ACTIVATION_EXIT_DELAY + return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY) ``` ### `get_churn_limit` @@ -1121,11 +1121,11 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None: exit_queue_epoch = max(exit_epochs + [get_delayed_activation_exit_epoch(get_current_epoch(state))]) exit_queue_churn = len([v for v in state.validator_registry if v.exit_epoch == exit_queue_epoch]) if exit_queue_churn >= get_churn_limit(state): - exit_queue_epoch += 1 + exit_queue_epoch += Epoch(1) # Set validator exit epoch and withdrawable epoch validator.exit_epoch = exit_queue_epoch - validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY + validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY) ``` #### `slash_validator` @@ -1140,15 +1140,15 @@ def slash_validator(state: BeaconState, current_epoch = get_current_epoch(state) initiate_validator_exit(state, slashed_index) state.validator_registry[slashed_index].slashed = True - state.validator_registry[slashed_index].withdrawable_epoch = current_epoch + LATEST_SLASHED_EXIT_LENGTH + state.validator_registry[slashed_index].withdrawable_epoch = Epoch(current_epoch + LATEST_SLASHED_EXIT_LENGTH) slashed_balance = state.validator_registry[slashed_index].effective_balance state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance proposer_index = get_beacon_proposer_index(state) if whistleblower_index is None: whistleblower_index = proposer_index - whistleblowing_reward = slashed_balance // WHISTLEBLOWING_REWARD_QUOTIENT - proposer_reward = whistleblowing_reward // PROPOSER_REWARD_QUOTIENT + whistleblowing_reward = Gwei(slashed_balance // WHISTLEBLOWING_REWARD_QUOTIENT) + proposer_reward = Gwei(whistleblowing_reward // PROPOSER_REWARD_QUOTIENT) increase_balance(state, proposer_index, proposer_reward) increase_balance(state, whistleblower_index, whistleblowing_reward - proposer_reward) decrease_balance(state, slashed_index, whistleblowing_reward) @@ -1226,7 +1226,7 @@ def process_slots(state: BeaconState, slot: Slot) -> None: # Process epoch on the first slot of the next epoch if (state.slot + 1) % SLOTS_PER_EPOCH == 0: process_epoch(state) - state.slot += 1 + state.slot += Slot(1) ``` ```python @@ -1293,7 +1293,7 @@ def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> List[Pen ```python def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]: - output = set() + output = set() # type: Set[ValidatorIndex] for a in attestations: output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield)) return sorted(filter(lambda index: not state.validator_registry[index].slashed, list(output))) @@ -1379,7 +1379,7 @@ def process_crosslinks(state: BeaconState) -> None: state.previous_crosslinks = [c for c in state.current_crosslinks] for epoch in (get_previous_epoch(state), get_current_epoch(state)): for offset in range(get_epoch_committee_count(state, epoch)): - shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT + shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT) crosslink_committee = get_crosslink_committee(state, epoch, shard) winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee): @@ -1392,17 +1392,17 @@ def process_crosslinks(state: BeaconState) -> None: def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: total_balance = get_total_active_balance(state) effective_balance = state.validator_registry[index].effective_balance - return effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH + return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH) ``` ```python def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: previous_epoch = get_previous_epoch(state) total_balance = get_total_active_balance(state) - rewards = [0 for _ in range(len(state.validator_registry))] - penalties = [0 for _ in range(len(state.validator_registry))] + rewards = [Gwei(0) for index in range(len(state.validator_registry))] + penalties = [Gwei(0) for index in range(len(state.validator_registry))] eligible_validator_indices = [ - index for index, v in enumerate(state.validator_registry) + ValidatorIndex(index) for index, v in enumerate(state.validator_registry) if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch) ] @@ -1421,21 +1421,23 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: # Proposer and inclusion delay micro-rewards for index in get_unslashed_attesting_indices(state, matching_source_attestations): + index = ValidatorIndex(index) attestation = min([ a for a in matching_source_attestations if index in get_attesting_indices(state, a.data, a.aggregation_bitfield) ], key=lambda a: a.inclusion_delay) - rewards[attestation.proposer_index] += get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT - rewards[index] += get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay + rewards[attestation.proposer_index] += Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT) + rewards[index] += Gwei(get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay) # Inactivity penalty finality_delay = previous_epoch - state.finalized_epoch if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY: matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations) for index in eligible_validator_indices: - penalties[index] += BASE_REWARDS_PER_EPOCH * get_base_reward(state, index) + index = ValidatorIndex(index) + penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index)) if index not in matching_target_attesting_indices: - penalties[index] += ( + penalties[index] += Gwei( state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT ) @@ -1444,11 +1446,11 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: ```python def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: - rewards = [0 for index in range(len(state.validator_registry))] - penalties = [0 for index in range(len(state.validator_registry))] + rewards = [Gwei(0) for index in range(len(state.validator_registry))] + penalties = [Gwei(0) for index in range(len(state.validator_registry))] epoch = get_previous_epoch(state) for offset in range(get_epoch_committee_count(state, epoch)): - shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT + shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT) crosslink_committee = get_crosslink_committee(state, epoch, shard) winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) attesting_balance = get_total_balance(state, attesting_indices) @@ -1469,9 +1471,9 @@ def process_rewards_and_penalties(state: BeaconState) -> None: rewards1, penalties1 = get_attestation_deltas(state) rewards2, penalties2 = get_crosslink_deltas(state) - for i in range(len(state.validator_registry)): - increase_balance(state, i, rewards1[i] + rewards2[i]) - decrease_balance(state, i, penalties1[i] + penalties2[i]) + for index in range(len(state.validator_registry)): + increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index]) + decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index]) ``` #### Registry updates @@ -1487,7 +1489,7 @@ def process_registry_updates(state: BeaconState) -> None: validator.activation_eligibility_epoch = get_current_epoch(state) if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: - initiate_validator_exit(state, index) + initiate_validator_exit(state, ValidatorIndex(index)) # Queue validators eligible for activation and not dequeued for activation prior to finalized epoch activation_queue = sorted([ @@ -1520,7 +1522,7 @@ def process_slashings(state: BeaconState) -> None: validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT ) - decrease_balance(state, index, penalty) + decrease_balance(state, ValidatorIndex(index), penalty) ``` #### Final updates @@ -1539,11 +1541,11 @@ def process_final_updates(state: BeaconState) -> None: if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance: validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) # Update start shard - state.latest_start_shard = (state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT + state.latest_start_shard = Shard((state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT) # Set active index root index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH state.latest_active_index_roots[index_root_position] = hash_tree_root( - get_active_validator_indices(state, next_epoch + ACTIVATION_EXIT_DELAY) + get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY)) ) # Set total slashed balances state.latest_slashed_balances[next_epoch % LATEST_SLASHED_EXIT_LENGTH] = ( @@ -1771,7 +1773,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: state.balances.append(amount) else: # Increase balance by deposit amount - index = validator_pubkeys.index(pubkey) + index = ValidatorIndex(validator_pubkeys.index(pubkey)) increase_balance(state, index, amount) ``` diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index cde1586c14..25851f331b 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -254,7 +254,7 @@ def __init__(self, *args: Iterable): # cannot check non-type objects, or parametrized types if isinstance(cls.elem_type, type) and not hasattr(cls.elem_type, '__args__'): for i, item in enumerate(self.items): - if not issubclass(type(item), cls.elem_type): + if not issubclass(cls.elem_type, type(item)): raise TypeError("Typed vector cannot hold differently typed value" " at index %d. Got type: %s, expected type: %s" % (i, type(item), cls.elem_type)) From 6f526add79d904f6230400eff7dbcb6dbab0c8b3 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 11 Jun 2019 00:40:07 -0400 Subject: [PATCH 04/21] flake8 length --- specs/core/0_beacon-chain.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a6bfd5e1ac..57bc2673f1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1427,7 +1427,9 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: if index in get_attesting_indices(state, a.data, a.aggregation_bitfield) ], key=lambda a: a.inclusion_delay) rewards[attestation.proposer_index] += Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT) - rewards[index] += Gwei(get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay) + rewards[index] += Gwei( + get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay + ) # Inactivity penalty finality_delay = previous_epoch - state.finalized_epoch From f2c33529df6c7d724277fb4329c3cf623444ca4a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 11 Jun 2019 00:40:25 -0400 Subject: [PATCH 05/21] Add mypy check in CI --- Makefile | 4 +++- test_libs/pyspec/requirements-testing.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f79b89dada..87439559fd 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,9 @@ citest: $(PY_SPEC_ALL_TARGETS) lint: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); . venv/bin/activate; \ - flake8 --ignore=E252,W504,W503 --max-line-length=120 ./eth2spec; + flake8 --ignore=E252,W504,W503 --max-line-length=120 ./eth2spec; \ + cd ./eth2spec; \ + mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs --disallow-any-generics -p phase0 install_deposit_contract_test: $(PY_SPEC_ALL_TARGETS) cd $(DEPOSIT_CONTRACT_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install -r requirements-testing.txt diff --git a/test_libs/pyspec/requirements-testing.txt b/test_libs/pyspec/requirements-testing.txt index 331d0fa284..1ae21a2f24 100644 --- a/test_libs/pyspec/requirements-testing.txt +++ b/test_libs/pyspec/requirements-testing.txt @@ -2,3 +2,4 @@ pytest>=3.6,<3.7 ../config_helpers flake8==3.7.7 +mypy==0.701 From 7a366828baf1a3a1ba34074b45becc01cbedd2e8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 12 Jun 2019 14:54:00 -0400 Subject: [PATCH 06/21] Make phase0 pass --- scripts/build_spec.py | 2 ++ specs/core/0_beacon-chain.md | 6 +++--- test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py | 12 ++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index f396d3b9c5..a4a97ab575 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -13,6 +13,7 @@ PHASE0_IMPORTS = '''from typing import ( Any, + Callable, Dict, List, Set, @@ -39,6 +40,7 @@ ''' PHASE1_IMPORTS = '''from typing import ( Any, + Callable, Dict, List, Set, diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 57bc2673f1..86c22c9764 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1634,15 +1634,15 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: assert len(body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index) # Verify that there are no duplicate transfers assert len(body.transfers) == len(set(body.transfers)) - - for operations, max_operations, function in ( + all_operations = [ (body.proposer_slashings, MAX_PROPOSER_SLASHINGS, process_proposer_slashing), (body.attester_slashings, MAX_ATTESTER_SLASHINGS, process_attester_slashing), (body.attestations, MAX_ATTESTATIONS, process_attestation), (body.deposits, MAX_DEPOSITS, process_deposit), (body.voluntary_exits, MAX_VOLUNTARY_EXITS, process_voluntary_exit), (body.transfers, MAX_TRANSFERS, process_transfer), - ): + ] # type: List[Tuple[List[Container], int, Callable]] + for operations, max_operations, function in all_operations: assert len(operations) <= max_operations for operation in operations: function(state, operation) diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 25851f331b..b75a40403a 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -414,12 +414,12 @@ class Bytes96(BytesN): # SSZ Defaults # ----------------------------- def get_zero_value(typ): - if is_list_type(typ): + if is_uint_type(typ): + return uint64(0) + elif is_list_type(typ): return [] elif is_bool_type(typ): return False - elif is_uint_type(typ): - return uint64(0) elif is_vector_type(typ): return typ() elif is_bytesn_type(typ): @@ -437,12 +437,12 @@ def get_zero_value(typ): def infer_type(obj): - if isinstance(obj, int): + if is_uint_type(obj.__class__): + return obj.__class__ + elif isinstance(obj, int): return uint64 elif isinstance(obj, list): return List[infer_type(obj[0])] - elif is_uint_type(obj.__class__): - return obj.__class__ elif isinstance(obj, (Vector, Container, bool, BytesN, bytes)): return obj.__class__ else: From 8a54203796503a873780377e180c8c19d143ec6a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 12 Jun 2019 16:50:49 -0400 Subject: [PATCH 07/21] Modify the mypy config --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 87439559fd..26fe3a3876 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ lint: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); . venv/bin/activate; \ flake8 --ignore=E252,W504,W503 --max-line-length=120 ./eth2spec; \ cd ./eth2spec; \ - mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs --disallow-any-generics -p phase0 + mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs -p phase0 install_deposit_contract_test: $(PY_SPEC_ALL_TARGETS) cd $(DEPOSIT_CONTRACT_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install -r requirements-testing.txt From 48e8164e28aeb73d7bc9108a89c40bff60ef2e42 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 12 Jun 2019 20:08:19 -0400 Subject: [PATCH 08/21] Add phase1 type hinting checks and fix many bugs --- scripts/build_spec.py | 1 + specs/core/1_custody-game.md | 62 ++++++++++++++++--------------- specs/core/1_shard-data-chains.md | 34 ++++++++--------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index a4a97ab575..3fb1dda7ea 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -43,6 +43,7 @@ Callable, Dict, List, + Optional, Set, Tuple, ) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 6c89ef8531..9e8414a427 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -184,7 +184,7 @@ class CustodyResponse(Container): ```python class CustodyKeyReveal(Container): # Index of the validator whose key is being revealed - revealer_index: uint64 + revealer_index: ValidatorIndex # Reveal (masked signature) reveal: Bytes96 ``` @@ -198,7 +198,7 @@ class EarlyDerivedSecretReveal(Container): # Index of the validator whose key is being revealed revealed_index: uint64 # RANDAO epoch of the key that is being revealed - epoch: uint64 + epoch: Epoch # Reveal (masked signature) reveal: Bytes96 # Index of the validator who revealed (whistleblower) @@ -251,7 +251,7 @@ class BeaconBlockBody(Container): ### `ceillog2` ```python -def ceillog2(x): +def ceillog2(x: int) -> int: return x.bit_length() ``` @@ -269,7 +269,7 @@ def get_custody_chunk_count(crosslink: Crosslink) -> int: ```python def get_custody_chunk_bit(key: Bytes96, chunk: bytes) -> bool: # TODO: Replace with something MPC-friendly, e.g. the Legendre symbol - return get_bitfield_bit(hash(key + chunk), 0) + return bool(get_bitfield_bit(hash(key + chunk), 0)) ``` ### `get_chunk_bits_root` @@ -288,7 +288,7 @@ def get_chunk_bits_root(chunk_bitfield: bytes) -> Bytes32: ```python def get_randao_epoch_for_custody_period(period: int, validator_index: ValidatorIndex) -> Epoch: next_period_start = (period + 1) * EPOCHS_PER_CUSTODY_PERIOD - validator_index % EPOCHS_PER_CUSTODY_PERIOD - return next_period_start + CUSTODY_PERIOD_TO_RANDAO_PADDING + return Epoch(next_period_start + CUSTODY_PERIOD_TO_RANDAO_PADDING) ``` ### `get_validators_custody_reveal_period` @@ -372,7 +372,11 @@ def process_custody_key_reveal(state: BeaconState, # Reward Block Preposer proposer_index = get_beacon_proposer_index(state) - increase_balance(state, proposer_index, get_base_reward(state, reveal.revealer_index) // MINOR_REWARD_QUOTIENT) + increase_balance( + state, + proposer_index, + Gwei(get_base_reward(state, reveal.revealer_index) // MINOR_REWARD_QUOTIENT) + ) ``` #### Early derived secret reveals @@ -433,7 +437,7 @@ def process_early_derived_secret_reveal(state: BeaconState, // len(get_active_validator_indices(state, get_current_epoch(state))) // PROPOSER_REWARD_QUOTIENT ) - penalty = ( + penalty = Gwei( max_proposer_slot_reward * EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE * (len(state.exposed_derived_secrets[derived_secret_location]) + 1) @@ -442,8 +446,8 @@ def process_early_derived_secret_reveal(state: BeaconState, # Apply penalty proposer_index = get_beacon_proposer_index(state) whistleblower_index = reveal.masker_index - whistleblowing_reward = penalty // WHISTLEBLOWING_REWARD_QUOTIENT - proposer_reward = whistleblowing_reward // PROPOSER_REWARD_QUOTIENT + whistleblowing_reward = Gwei(penalty // WHISTLEBLOWING_REWARD_QUOTIENT) + proposer_reward = Gwei(whistleblowing_reward // PROPOSER_REWARD_QUOTIENT) increase_balance(state, proposer_index, proposer_reward) increase_balance(state, whistleblower_index, whistleblowing_reward - proposer_reward) decrease_balance(state, reveal.revealed_index, penalty) @@ -512,7 +516,7 @@ def process_bit_challenge(state: BeaconState, pubkey=challenger.pubkey, message_hash=signing_root(challenge), signature=challenge.signature, - domain=get_domain(state, get_current_epoch(state), DOMAIN_CUSTODY_BIT_CHALLENGE), + domain=get_domain(state, DOMAIN_CUSTODY_BIT_CHALLENGE, get_current_epoch(state)), ) assert is_slashable_validator(challenger, get_current_epoch(state)) @@ -535,8 +539,8 @@ def process_bit_challenge(state: BeaconState, # Verify the responder is a valid custody key epoch_to_sign = get_randao_epoch_for_custody_period( get_validators_custody_reveal_period( - state=state, - index=challenge.responder_index, + state, + challenge.responder_index, epoch=slot_to_epoch(attestation.data.slot)), challenge.responder_index ) @@ -610,7 +614,7 @@ def process_chunk_challenge_response(state: BeaconState, # Verify the chunk matches the crosslink data root assert verify_merkle_branch( leaf=hash_tree_root(response.chunk), - branch=response.data_branch, + proof=response.data_branch, depth=challenge.depth, index=response.chunk_index, root=challenge.data_root, @@ -620,7 +624,7 @@ def process_chunk_challenge_response(state: BeaconState, records[records.index(challenge)] = CustodyChunkChallengeRecord() # Reward the proposer proposer_index = get_beacon_proposer_index(state) - increase_balance(state, proposer_index, get_base_reward(state, proposer_index) // MINOR_REWARD_QUOTIENT) + increase_balance(state, proposer_index, Gwei(get_base_reward(state, proposer_index) // MINOR_REWARD_QUOTIENT)) ``` ```python @@ -635,7 +639,7 @@ def process_bit_challenge_response(state: BeaconState, # Verify the chunk matches the crosslink data root assert verify_merkle_branch( leaf=hash_tree_root(response.chunk), - branch=response.data_branch, + proof=response.data_branch, depth=ceillog2(challenge.chunk_count), index=response.chunk_index, root=challenge.data_root, @@ -643,7 +647,7 @@ def process_bit_challenge_response(state: BeaconState, # Verify the chunk bit leaf matches the challenge data assert verify_merkle_branch( leaf=response.chunk_bits_leaf, - branch=response.chunk_bits_branch, + proof=response.chunk_bits_branch, depth=ceillog2(challenge.chunk_count) >> 8, index=response.chunk_index // 256, root=challenge.chunk_bits_merkle_root @@ -671,8 +675,8 @@ Run `process_reveal_deadlines(state)` immediately after `process_registry_update def process_reveal_deadlines(state: BeaconState) -> None: for index, validator in enumerate(state.validator_registry): deadline = validator.next_custody_reveal_period + (CUSTODY_RESPONSE_DEADLINE // EPOCHS_PER_CUSTODY_PERIOD) - if get_validators_custody_reveal_period(state, index) > deadline: - slash_validator(state, index) + if get_validators_custody_reveal_period(state, ValidatorIndex(index)) > deadline: + slash_validator(state, ValidatorIndex(index)) ``` Run `process_challenge_deadlines(state)` immediately after `process_reveal_deadlines(state)`: @@ -682,17 +686,17 @@ Run `process_challenge_deadlines(state)` immediately after `process_reveal_deadl process_challenge_deadlines(state) # end insert @process_challenge_deadlines def process_challenge_deadlines(state: BeaconState) -> None: - for challenge in state.custody_chunk_challenge_records: - if get_current_epoch(state) > challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE: - slash_validator(state, challenge.responder_index, challenge.challenger_index) - records = state.custody_chunk_challenge_records - records[records.index(challenge)] = CustodyChunkChallengeRecord() - - for challenge in state.custody_bit_challenge_records: - if get_current_epoch(state) > challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE: - slash_validator(state, challenge.responder_index, challenge.challenger_index) + for custody_chunk_challenge in state.custody_chunk_challenge_records: + if get_current_epoch(state) > custody_chunk_challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE: + slash_validator(state, custody_chunk_challenge.responder_index, custody_chunk_challenge.challenger_index) + records = state.custody_chunk_challenge + records[records.index(custody_chunk_challenge)] = CustodyChunkChallengeRecord() + + for custody_bit_challenge in state.custody_bit_challenge_records: + if get_current_epoch(state) > custody_bit_challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE: + slash_validator(state, custody_bit_challenge.responder_index, custody_bit_challenge.challenger_index) records = state.custody_bit_challenge_records - records[records.index(challenge)] = CustodyBitChallengeRecord() + records[records.index(custody_bit_challenge)] = CustodyBitChallengeRecord() ``` Append this to `process_final_updates(state)`: @@ -713,5 +717,5 @@ def after_process_final_updates(state: BeaconState) -> None: for index, validator in enumerate(state.validator_registry): if index not in validator_indices_in_records: if validator.exit_epoch != FAR_FUTURE_EPOCH and validator.withdrawable_epoch == FAR_FUTURE_EPOCH: - validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY + validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY) ``` diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 21e08e7c96..ce6f0a6c28 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -79,8 +79,8 @@ class ShardBlockBody(Container): ```python class ShardAttestation(Container): class data(Container): - slot: uint64 - shard: uint64 + slot: Slot + shard: Shard shard_block_root: Bytes32 aggregation_bitfield: bytes aggregate_signature: Bytes96 @@ -90,8 +90,8 @@ class ShardAttestation(Container): ```python class ShardBlock(Container): - slot: uint64 - shard: uint64 + slot: Slot + shard: Shard beacon_chain_root: Bytes32 parent_root: Bytes32 data: ShardBlockBody @@ -104,8 +104,8 @@ class ShardBlock(Container): ```python class ShardBlockHeader(Container): - slot: uint64 - shard: uint64 + slot: Slot + shard: Shard beacon_chain_root: Bytes32 parent_root: Bytes32 body_root: Bytes32 @@ -138,8 +138,8 @@ def get_period_committee(state: BeaconState, ### `get_switchover_epoch` ```python -def get_switchover_epoch(state: BeaconState, epoch: Epoch, index: ValidatorIndex): - earlier_start_epoch = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2 +def get_switchover_epoch(state: BeaconState, epoch: Epoch, index: ValidatorIndex) -> int: + earlier_start_epoch = Epoch(epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2) return (bytes_to_int(hash(generate_seed(state, earlier_start_epoch) + int_to_bytes(index, length=3)[0:8])) % PERSISTENT_COMMITTEE_PERIOD) ``` @@ -154,19 +154,19 @@ def get_persistent_committee(state: BeaconState, Return the persistent committee for the given ``shard`` at the given ``slot``. """ epoch = slot_to_epoch(slot) - earlier_start_epoch = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2 - later_start_epoch = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD + earlier_start_epoch = Epoch(epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2) + later_start_epoch = Epoch(epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD) committee_count = max( - len(get_active_validator_indices(state.validator_registry, earlier_start_epoch)) // + len(get_active_validator_indices(state, earlier_start_epoch)) // (SHARD_COUNT * TARGET_COMMITTEE_SIZE), - len(get_active_validator_indices(state.validator_registry, later_start_epoch)) // + len(get_active_validator_indices(state, later_start_epoch)) // (SHARD_COUNT * TARGET_COMMITTEE_SIZE), ) + 1 index = slot % committee_count - earlier_committee = get_period_committee(state, shard, earlier_start_epoch, index, committee_count) - later_committee = get_period_committee(state, shard, later_start_epoch, index, committee_count) + earlier_committee = get_period_committee(state, earlier_start_epoch, shard, index, committee_count) + later_committee = get_period_committee(state, later_start_epoch, shard, index, committee_count) # Take not-yet-cycled-out validators from earlier committee and already-cycled-in validators from # later committee; return a sorted list of the union of the two, deduplicated @@ -181,7 +181,7 @@ def get_persistent_committee(state: BeaconState, ```python def get_shard_proposer_index(state: BeaconState, shard: Shard, - slot: Slot) -> ValidatorIndex: + slot: Slot) -> Optional[ValidatorIndex]: # Randomly shift persistent committee persistent_committee = get_persistent_committee(state, shard, slot) seed = hash(state.current_shuffling_seed + int_to_bytes(shard, length=8) + int_to_bytes(slot, length=8)) @@ -231,7 +231,7 @@ def verify_shard_attestation_signature(state: BeaconState, pubkey=bls_aggregate_pubkeys(pubkeys), message_hash=data.shard_block_root, signature=attestation.aggregate_signature, - domain=get_domain(state, slot_to_epoch(data.slot), DOMAIN_SHARD_ATTESTER) + domain=get_domain(state, DOMAIN_SHARD_ATTESTER, slot_to_epoch(data.slot)) ) ``` @@ -328,7 +328,7 @@ def is_valid_shard_block(beacon_blocks: List[BeaconBlock], pubkey=beacon_state.validator_registry[proposer_index].pubkey, message_hash=signing_root(block), signature=candidate.signature, - domain=get_domain(beacon_state, slot_to_epoch(candidate.slot), DOMAIN_SHARD_PROPOSER), + domain=get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, slot_to_epoch(candidate.slot)), ) return True From 8577cff72eedc2d99eec7e2cc288715834de8a36 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 12 Jun 2019 20:10:24 -0400 Subject: [PATCH 09/21] enable mypy check in CI --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 26fe3a3876..ca59d6c8a9 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,8 @@ lint: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); . venv/bin/activate; \ flake8 --ignore=E252,W504,W503 --max-line-length=120 ./eth2spec; \ cd ./eth2spec; \ - mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs -p phase0 + mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs -p phase0; \ + mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs -p phase1 install_deposit_contract_test: $(PY_SPEC_ALL_TARGETS) cd $(DEPOSIT_CONTRACT_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install -r requirements-testing.txt From 00a68e28b50cb0c1067319d31c75d368b352b822 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 15 Jun 2019 16:57:50 -0400 Subject: [PATCH 10/21] Define Custom Types via function_puller --- scripts/build_spec.py | 17 ++++---- scripts/function_puller.py | 22 +++++----- specs/core/0_beacon-chain.md | 40 +++++++++---------- .../pyspec/eth2spec/utils/ssz/ssz_typing.py | 2 +- 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 3fb1dda7ea..6bcb04656d 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -128,11 +128,11 @@ def apply_constants_preset(preset: Dict[str, Any]) -> None: def objects_to_spec(functions: Dict[str, str], + custom_types: Dict[str, str], constants: Dict[str, str], ssz_objects: Dict[str, str], inserts: Dict[str, str], imports: Dict[str, str], - new_types: Dict[str, str], byte_types: List[int], ) -> str: """ @@ -144,7 +144,7 @@ def objects_to_spec(functions: Dict[str, str], f"class {key}({value}):\n" f" def __init__(self, _x: uint64) -> None:\n" f" ...\n" - for key, value in new_types.items() + for key, value in custom_types.items() ] ) ) @@ -225,18 +225,19 @@ def combine_spec_objects(spec0: SpecObject, spec1: SpecObject) -> SpecObject: """ Takes in two spec variants (as tuples of their objects) and combines them using the appropriate combiner function. """ - functions0, constants0, ssz_objects0, inserts0 = spec0 - functions1, constants1, ssz_objects1, inserts1 = spec1 + functions0, custom_types0, constants0, ssz_objects0, inserts0 = spec0 + functions1, custom_types1, constants1, ssz_objects1, inserts1 = spec1 functions = combine_functions(functions0, functions1) + custom_types = combine_constants(custom_types0, custom_types1) constants = combine_constants(constants0, constants1) ssz_objects = combine_ssz_objects(ssz_objects0, ssz_objects1) inserts = combine_inserts(inserts0, inserts1) - return functions, constants, ssz_objects, inserts + return functions, custom_types, constants, ssz_objects, inserts def build_phase0_spec(sourcefile: str, outfile: str=None) -> Optional[str]: - functions, constants, ssz_objects, inserts = get_spec(sourcefile) - spec = objects_to_spec(functions, constants, ssz_objects, inserts, PHASE0_IMPORTS, NEW_TYPES, BYTE_TYPES) + functions, custom_types, constants, ssz_objects, inserts = get_spec(sourcefile) + spec = objects_to_spec(functions, custom_types, constants, ssz_objects, inserts, PHASE0_IMPORTS, BYTE_TYPES) if outfile is not None: with open(outfile, 'w') as out: out.write(spec) @@ -253,7 +254,7 @@ def build_phase1_spec(phase0_sourcefile: str, spec_objects = phase0_spec for value in [phase1_custody, phase1_shard_data]: spec_objects = combine_spec_objects(spec_objects, value) - spec = objects_to_spec(*spec_objects, PHASE1_IMPORTS, NEW_TYPES, BYTE_TYPES) + spec = objects_to_spec(*spec_objects, PHASE1_IMPORTS, BYTE_TYPES) if outfile is not None: with open(outfile, 'w') as out: out.write(spec) diff --git a/scripts/function_puller.py b/scripts/function_puller.py index 303d4ec2f5..4ad9eef57c 100644 --- a/scripts/function_puller.py +++ b/scripts/function_puller.py @@ -29,6 +29,7 @@ def get_spec(file_name: str) -> SpecObject: inserts = {} function_matcher = re.compile(FUNCTION_REGEX) inserts_matcher = re.compile(BEGIN_INSERT_REGEX) + custom_types = {} for linenum, line in enumerate(open(file_name).readlines()): line = line.rstrip() if pulling_from is None and len(line) > 0 and line[0] == '#' and line[-1] == '`': @@ -64,7 +65,7 @@ def get_spec(file_name: str) -> SpecObject: ssz_objects[current_name] = ssz_objects.get(current_name, '') + line + '\n' else: functions[current_name] = functions.get(current_name, '') + line + '\n' - # Handle constant table entries + # Handle constant and custom types table entries elif pulling_from is None and len(line) > 0 and line[0] == '|': row = line[1:].split('|') if len(row) >= 2: @@ -72,12 +73,15 @@ def get_spec(file_name: str) -> SpecObject: row[i] = row[i].strip().strip('`') if '`' in row[i]: row[i] = row[i][:row[i].find('`')] - eligible = True - if row[0][0] not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_': - eligible = False - for c in row[0]: - if c not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789': + if row[1].startswith('uint') or row[1].startswith('bytes'): + custom_types[row[0]] = row[1] + else: + eligible = True + if row[0][0] not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_': eligible = False - if eligible: - constants[row[0]] = row[1].replace('**TBD**', '0x1234567890123456789012345678901234567890') - return functions, constants, ssz_objects, inserts + for c in row[0]: + if c not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789': + eligible = False + if eligible: + constants[row[0]] = row[1].replace('**TBD**', '0x1234567890123456789012345678901234567890') + return functions, custom_types, constants, ssz_objects, inserts diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 86c22c9764..8baba6928f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -10,6 +10,7 @@ - [Introduction](#introduction) - [Notation](#notation) - [Terminology](#terminology) + - [Custom types](#custom-types) - [Constants](#constants) - [Misc](#misc) - [Deposit contract](#deposit-contract) @@ -45,7 +46,6 @@ - [`BeaconBlock`](#beaconblock) - [Beacon state](#beacon-state) - [`BeaconState`](#beaconstate) - - [Custom types](#custom-types) - [Helper functions](#helper-functions) - [`xor`](#xor) - [`hash`](#hash) @@ -150,6 +150,20 @@ Code snippets appearing in `this style` are to be interpreted as Python code. * **Withdrawal period**—the number of slots between a [validator](#dfn-validator) exit and the [validator](#dfn-validator) balance being withdrawable. * **Genesis time**—the Unix time of the genesis beacon chain block at slot 0. +## Custom types + +We define the following Python custom types for type hinting and readability: + +| Name | SSZ equivalent | Description | +| - | - | - | +| `Slot` | `uint64` | a slot number | +| `Epoch` | `uint64` | an epoch number | +| `Shard` | `uint64` | a shard number | +| `ValidatorIndex` | `uint64` | a validator registry index | +| `Gwei` | `uint64` | an amount in Gwei | +| `BLSPubkey` | `Bytes48` | a BLS12-381 public key | +| `BLSSignature` | `Bytes96` | a BLS12-381 signature | + ## Constants *Note*: The default mainnet values for the constants are included here for spec-design purposes. @@ -178,12 +192,12 @@ These configurations are updated for releases, but may be out of sync during `de ### Gwei values -| Name | Value | Unit | +| Name | Value | | - | - | :-: | -| `MIN_DEPOSIT_AMOUNT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | Gwei | -| `MAX_EFFECTIVE_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | Gwei | -| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) | Gwei | -| `EFFECTIVE_BALANCE_INCREMENT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | Gwei | +| `MIN_DEPOSIT_AMOUNT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | +| `MAX_EFFECTIVE_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | +| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) | +| `EFFECTIVE_BALANCE_INCREMENT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | ### Initial values @@ -563,20 +577,6 @@ class BeaconState(Container): deposit_index: uint64 ``` -## Custom types - -We define the following Python custom types for type hinting and readability: - -| Name | SSZ equivalent | Description | -| - | - | - | -| `Slot` | `uint64` | a slot number | -| `Epoch` | `uint64` | an epoch number | -| `Shard` | `uint64` | a shard number | -| `ValidatorIndex` | `uint64` | a validator registry index | -| `Gwei` | `uint64` | an amount in Gwei | -| `BLSPubkey` | `Bytes48` | a BLS12-381 public key | -| `BLSSignature` | `Bytes96` | a BLS12-381 signature | - ## Helper functions *Note*: The definitions below are for specification purposes and are not necessarily optimal implementations. diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index b75a40403a..cbd313d85f 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -51,7 +51,7 @@ class uint64(uint): def __new__(cls, value, *args, **kwargs): if value.bit_length() > 64: - raise ValueError("value out of bounds for uint128") + raise ValueError("value out of bounds for uint64") return super().__new__(cls, value) From b772b03847d90e52b5c0f79df893f416b655fb6f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 15 Jun 2019 17:23:44 -0400 Subject: [PATCH 11/21] Handle `BLSPubkey` and `BLSSignature` --- scripts/build_spec.py | 14 ++++++++------ scripts/function_puller.py | 2 +- specs/core/0_beacon-chain.md | 22 +++++++++++----------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 6bcb04656d..8f0048b8f7 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -142,8 +142,10 @@ def objects_to_spec(functions: Dict[str, str], '\n\n'.join( [ f"class {key}({value}):\n" - f" def __init__(self, _x: uint64) -> None:\n" + f" def __init__(self, _x: {value}) -> None:\n" f" ...\n" + if value.startswith("uint") + else f"class {key}({value}):\n pass\n" for key, value in custom_types.items() ] ) @@ -185,7 +187,7 @@ def combine_constants(old_constants: Dict[str, str], new_constants: Dict[str, st return old_constants -def dependency_order_ssz_objects(objects: Dict[str, str]) -> None: +def dependency_order_ssz_objects(objects: Dict[str, str], custom_types: Dict[str, str]) -> None: """ Determines which SSZ Object is depenedent on which other and orders them appropriately """ @@ -194,14 +196,14 @@ def dependency_order_ssz_objects(objects: Dict[str, str]) -> None: dependencies = re.findall(r'(: [A-Z][\w[]*)', value) dependencies = map(lambda x: re.sub(r'\W|Vector|List|Container|uint\d+|Bytes\d+|bytes', '', x), dependencies) for dep in dependencies: - if dep in NEW_TYPES or len(dep) == 0: + if dep in custom_types or len(dep) == 0: continue key_list = list(objects.keys()) for item in [dep, key] + key_list[key_list.index(dep)+1:]: objects[item] = objects.pop(item) -def combine_ssz_objects(old_objects: Dict[str, str], new_objects: Dict[str, str]) -> Dict[str, str]: +def combine_ssz_objects(old_objects: Dict[str, str], new_objects: Dict[str, str], custom_types) -> Dict[str, str]: """ Takes in old spec and new spec ssz objects, combines them, and returns the newer versions of the objects in dependency order. @@ -213,7 +215,7 @@ def combine_ssz_objects(old_objects: Dict[str, str], new_objects: Dict[str, str] # remove leading variable name value = re.sub(r'^class [\w]*\(Container\):\n', '', value) old_objects[key] = old_objects.get(key, '') + value - dependency_order_ssz_objects(old_objects) + dependency_order_ssz_objects(old_objects, custom_types) return old_objects @@ -230,7 +232,7 @@ def combine_spec_objects(spec0: SpecObject, spec1: SpecObject) -> SpecObject: functions = combine_functions(functions0, functions1) custom_types = combine_constants(custom_types0, custom_types1) constants = combine_constants(constants0, constants1) - ssz_objects = combine_ssz_objects(ssz_objects0, ssz_objects1) + ssz_objects = combine_ssz_objects(ssz_objects0, ssz_objects1, custom_types) inserts = combine_inserts(inserts0, inserts1) return functions, custom_types, constants, ssz_objects, inserts diff --git a/scripts/function_puller.py b/scripts/function_puller.py index 4ad9eef57c..0fd2fa4763 100644 --- a/scripts/function_puller.py +++ b/scripts/function_puller.py @@ -73,7 +73,7 @@ def get_spec(file_name: str) -> SpecObject: row[i] = row[i].strip().strip('`') if '`' in row[i]: row[i] = row[i][:row[i].find('`')] - if row[1].startswith('uint') or row[1].startswith('bytes'): + if row[1].startswith('uint') or row[1].startswith('Bytes'): custom_types[row[0]] = row[1] else: eligible = True diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8baba6928f..a45da28725 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -294,7 +294,7 @@ class Fork(Container): ```python class Validator(Container): # BLS public key - pubkey: Bytes48 + pubkey: BLSPubkey # Withdrawal credentials withdrawal_credentials: Bytes32 # Epoch when became eligible for activation @@ -363,7 +363,7 @@ class IndexedAttestation(Container): # Attestation data data: AttestationData # Aggregate signature - signature: Bytes96 + signature: BLSSignature ``` #### `PendingAttestation` @@ -407,13 +407,13 @@ class HistoricalBatch(Container): ```python class DepositData(Container): # BLS pubkey - pubkey: Bytes48 + pubkey: BLSPubkey # Withdrawal credentials withdrawal_credentials: Bytes32 # Amount in Gwei amount: Gwei # Container self-signature - signature: Bytes96 + signature: BLSSignature ``` #### `BeaconBlockHeader` @@ -424,7 +424,7 @@ class BeaconBlockHeader(Container): parent_root: Bytes32 state_root: Bytes32 body_root: Bytes32 - signature: Bytes96 + signature: BLSSignature ``` ### Beacon operations @@ -462,7 +462,7 @@ class Attestation(Container): # Custody bitfield custody_bitfield: bytes # BLS aggregate signature - signature: Bytes96 + signature: BLSSignature ``` #### `Deposit` @@ -484,7 +484,7 @@ class VoluntaryExit(Container): # Index of the exiting validator validator_index: ValidatorIndex # Validator signature - signature: Bytes96 + signature: BLSSignature ``` #### `Transfer` @@ -502,9 +502,9 @@ class Transfer(Container): # Inclusion slot slot: Slot # Sender withdrawal pubkey - pubkey: Bytes48 + pubkey: BLSPubkey # Sender signature - signature: Bytes96 + signature: BLSSignature ``` ### Beacon blocks @@ -513,7 +513,7 @@ class Transfer(Container): ```python class BeaconBlockBody(Container): - randao_reveal: Bytes96 + randao_reveal: BLSSignature eth1_data: Eth1Data graffiti: Bytes32 proposer_slashings: List[ProposerSlashing] @@ -533,7 +533,7 @@ class BeaconBlock(Container): parent_root: Bytes32 state_root: Bytes32 body: BeaconBlockBody - signature: Bytes96 + signature: BLSSignature ``` ### Beacon state From 9b77ec11f8e091992b74258f39e5633663c5903e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 15 Jun 2019 17:32:52 -0400 Subject: [PATCH 12/21] Version: Bytes4 --- scripts/build_spec.py | 7 ------- specs/core/0_beacon-chain.md | 5 +++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 8f0048b8f7..9f5d07b294 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -67,13 +67,6 @@ from eth2spec.utils.hash_function import hash ''' -NEW_TYPES = { - 'Slot': 'uint64', - 'Epoch': 'uint64', - 'Shard': 'uint64', - 'ValidatorIndex': 'uint64', - 'Gwei': 'uint64', -} BYTE_TYPES = [4, 32, 48, 96] SUNDRY_FUNCTIONS = ''' def get_ssz_type_by_name(name: str) -> Container: diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a45da28725..8b0c51b044 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -161,6 +161,7 @@ We define the following Python custom types for type hinting and readability: | `Shard` | `uint64` | a shard number | | `ValidatorIndex` | `uint64` | a validator registry index | | `Gwei` | `uint64` | an amount in Gwei | +| `Version` | `Bytes4` | a fork version number | | `BLSPubkey` | `Bytes48` | a BLS12-381 public key | | `BLSSignature` | `Bytes96` | a BLS12-381 signature | @@ -282,9 +283,9 @@ The types are defined topologically to aid in facilitating an executable version ```python class Fork(Container): # Previous fork version - previous_version: Bytes4 + previous_version: Version # Current fork version - current_version: Bytes4 + current_version: Version # Fork epoch number epoch: Epoch ``` From e93ba51ef807e7ae87c5f793c385112da1b8c0ab Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 15 Jun 2019 18:25:37 -0400 Subject: [PATCH 13/21] More clean up --- specs/core/1_custody-game.md | 18 +++++++++--------- specs/core/1_shard-data-chains.md | 6 +++--- specs/light_client/sync_protocol.md | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 9e8414a427..315084c301 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -133,9 +133,9 @@ class CustodyBitChallenge(Container): responder_index: ValidatorIndex attestation: Attestation challenger_index: ValidatorIndex - responder_key: Bytes96 + responder_key: BLSSignature chunk_bits: bytes - signature: Bytes96 + signature: BLSSignature ``` #### `CustodyChunkChallengeRecord` @@ -162,7 +162,7 @@ class CustodyBitChallengeRecord(Container): data_root: Bytes32 chunk_count: uint64 chunk_bits_merkle_root: Bytes32 - responder_key: Bytes96 + responder_key: BLSSignature ``` #### `CustodyResponse` @@ -186,7 +186,7 @@ class CustodyKeyReveal(Container): # Index of the validator whose key is being revealed revealer_index: ValidatorIndex # Reveal (masked signature) - reveal: Bytes96 + reveal: BLSSignature ``` #### `EarlyDerivedSecretReveal` @@ -196,13 +196,13 @@ Represents an early (punishable) reveal of one of the derived secrets, where der ```python class EarlyDerivedSecretReveal(Container): # Index of the validator whose key is being revealed - revealed_index: uint64 + revealed_index: ValidatorIndex # RANDAO epoch of the key that is being revealed epoch: Epoch # Reveal (masked signature) - reveal: Bytes96 + reveal: BLSSignature # Index of the validator who revealed (whistleblower) - masker_index: uint64 + masker_index: ValidatorIndex # Mask used to hide the actual reveal signature (prevent reveal from being stolen) mask: Bytes32 ``` @@ -232,7 +232,7 @@ class BeaconState(Container): # Future derived secrets already exposed; contains the indices of the exposed validator # at RANDAO reveal period % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS - exposed_derived_secrets: Vector[List[uint64], EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS] + exposed_derived_secrets: Vector[List[ValidatorIndex], EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS] ``` #### `BeaconBlockBody` @@ -267,7 +267,7 @@ def get_custody_chunk_count(crosslink: Crosslink) -> int: ### `get_custody_chunk_bit` ```python -def get_custody_chunk_bit(key: Bytes96, chunk: bytes) -> bool: +def get_custody_chunk_bit(key: BLSSignature, chunk: bytes) -> bool: # TODO: Replace with something MPC-friendly, e.g. the Legendre symbol return bool(get_bitfield_bit(hash(key + chunk), 0)) ``` diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index ce6f0a6c28..6b18d13f64 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -83,7 +83,7 @@ class ShardAttestation(Container): shard: Shard shard_block_root: Bytes32 aggregation_bitfield: bytes - aggregate_signature: Bytes96 + aggregate_signature: BLSSignature ``` ### `ShardBlock` @@ -97,7 +97,7 @@ class ShardBlock(Container): data: ShardBlockBody state_root: Bytes32 attestations: List[ShardAttestation] - signature: Bytes96 + signature: BLSSignature ``` ### `ShardBlockHeader` @@ -111,7 +111,7 @@ class ShardBlockHeader(Container): body_root: Bytes32 state_root: Bytes32 attestations: List[ShardAttestation] - signature: Bytes96 + signature: BLSSignature ``` ## Helper functions diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 8501c58690..dc2ce397be 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -167,7 +167,7 @@ If a client wants to update its `finalized_header` it asks the network for a `Bl ```python { 'header': BeaconBlockHeader, - 'shard_aggregate_signature': 'bytes96', + 'shard_aggregate_signature': BLSSignature, 'shard_bitfield': 'bytes', 'shard_parent_block': ShardBlock, } From 18ebd2aa9093b16b708be7261f510f5d96e2d3bd Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 17 Jun 2019 17:21:45 -0400 Subject: [PATCH 14/21] Bytes32 -> Hash --- scripts/build_spec.py | 20 ++++------ specs/core/0_beacon-chain.md | 71 ++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 9f5d07b294..01bcac76e3 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -75,21 +75,19 @@ def get_ssz_type_by_name(name: str) -> Container: # Monkey patch validator compute committee code _compute_committee = compute_committee -committee_cache: Dict[Tuple[Bytes32, Bytes32, int, int], List[ValidatorIndex]] = {} +committee_cache: Dict[Tuple[Hash, Hash, int, int], List[ValidatorIndex]] = {} def compute_committee(indices: List[ValidatorIndex], # type: ignore - seed: Bytes32, + seed: Hash, index: int, count: int) -> List[ValidatorIndex]: param_hash = (hash_tree_root(indices), seed, index, count) - if param_hash in committee_cache: - return committee_cache[param_hash] - else: + if param_hash not in committee_cache: ret = _compute_committee(indices, seed, index, count) committee_cache[param_hash] = ret - return ret + return committee_cache[param_hash] # Monkey patch hash cache @@ -97,13 +95,11 @@ def compute_committee(indices: List[ValidatorIndex], # type: ignore hash_cache: Dict[bytes, Bytes32] = {} -def hash(x: bytes) -> Bytes32: - if x in hash_cache: - return hash_cache[x] - else: +def hash(x: bytes) -> Hash: + if x not in hash_cache: ret = _hash(x) - hash_cache[x] = ret - return ret + hash_cache[x] = Hash(ret) + return hash_cache[x] # Access to overwrite spec constants based on configuration diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8b0c51b044..76dc6eb740 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -162,6 +162,7 @@ We define the following Python custom types for type hinting and readability: | `ValidatorIndex` | `uint64` | a validator registry index | | `Gwei` | `uint64` | an amount in Gwei | | `Version` | `Bytes4` | a fork version number | +| `Hash` | `Bytes32` | a hashed result | | `BLSPubkey` | `Bytes48` | a BLS12-381 public key | | `BLSSignature` | `Bytes96` | a BLS12-381 signature | @@ -297,7 +298,7 @@ class Validator(Container): # BLS public key pubkey: BLSPubkey # Withdrawal credentials - withdrawal_credentials: Bytes32 + withdrawal_credentials: Hash # Epoch when became eligible for activation activation_eligibility_epoch: Epoch # Epoch when validator activated @@ -322,9 +323,9 @@ class Crosslink(Container): start_epoch: Epoch end_epoch: Epoch # Root of the previous crosslink - parent_root: Bytes32 + parent_root: Hash # Root of the crosslinked shard data since the previous crosslink - data_root: Bytes32 + data_root: Hash ``` #### `AttestationData` @@ -332,13 +333,13 @@ class Crosslink(Container): ```python class AttestationData(Container): # LMD GHOST vote - beacon_block_root: Bytes32 + beacon_block_root: Hash # FFG vote source_epoch: Epoch - source_root: Bytes32 + source_root: Hash target_epoch: Epoch - target_root: Bytes32 + target_root: Hash # Crosslink vote crosslink: Crosslink @@ -386,11 +387,11 @@ class PendingAttestation(Container): ```python class Eth1Data(Container): # Root of the deposit tree - deposit_root: Bytes32 + deposit_root: Hash # Total number of deposits deposit_count: uint64 # Block hash - block_hash: Bytes32 + block_hash: Hash ``` #### `HistoricalBatch` @@ -398,9 +399,9 @@ class Eth1Data(Container): ```python class HistoricalBatch(Container): # Block roots - block_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] + block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] # State roots - state_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] + state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] ``` #### `DepositData` @@ -410,7 +411,7 @@ class DepositData(Container): # BLS pubkey pubkey: BLSPubkey # Withdrawal credentials - withdrawal_credentials: Bytes32 + withdrawal_credentials: Hash # Amount in Gwei amount: Gwei # Container self-signature @@ -422,9 +423,9 @@ class DepositData(Container): ```python class BeaconBlockHeader(Container): slot: Slot - parent_root: Bytes32 - state_root: Bytes32 - body_root: Bytes32 + parent_root: Hash + state_root: Hash + body_root: Hash signature: BLSSignature ``` @@ -471,7 +472,7 @@ class Attestation(Container): ```python class Deposit(Container): # Branch in the deposit tree - proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH] + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Data data: DepositData ``` @@ -531,8 +532,8 @@ class BeaconBlockBody(Container): class BeaconBlock(Container): # Header slot: Slot - parent_root: Bytes32 - state_root: Bytes32 + parent_root: Hash + state_root: Hash body: BeaconBlockBody signature: BLSSignature ``` @@ -551,27 +552,27 @@ class BeaconState(Container): validator_registry: List[Validator] balances: List[Gwei] # Randomness and committees - latest_randao_mixes: Vector[Bytes32, LATEST_RANDAO_MIXES_LENGTH] + latest_randao_mixes: Vector[Hash, LATEST_RANDAO_MIXES_LENGTH] latest_start_shard: Shard # Finality previous_epoch_attestations: List[PendingAttestation] current_epoch_attestations: List[PendingAttestation] previous_justified_epoch: Epoch current_justified_epoch: Epoch - previous_justified_root: Bytes32 - current_justified_root: Bytes32 + previous_justified_root: Hash + current_justified_root: Hash justification_bitfield: uint64 finalized_epoch: Epoch - finalized_root: Bytes32 + finalized_root: Hash # Recent state current_crosslinks: Vector[Crosslink, SHARD_COUNT] previous_crosslinks: Vector[Crosslink, SHARD_COUNT] - latest_block_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] - latest_state_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] - latest_active_index_roots: Vector[Bytes32, LATEST_ACTIVE_INDEX_ROOTS_LENGTH] + latest_block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] + latest_state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] + latest_active_index_roots: Vector[Hash, LATEST_ACTIVE_INDEX_ROOTS_LENGTH] latest_slashed_balances: Vector[Gwei, LATEST_SLASHED_EXIT_LENGTH] latest_block_header: BeaconBlockHeader - historical_roots: List[Bytes32] + historical_roots: List[Hash] # Ethereum 1.0 chain data latest_eth1_data: Eth1Data eth1_data_votes: List[Eth1Data] @@ -597,11 +598,11 @@ The `hash` function is SHA256. ### `hash_tree_root` -`def hash_tree_root(object: SSZSerializable) -> Bytes32` is a function for hashing objects into a single root utilizing a hash tree structure. `hash_tree_root` is defined in the [SimpleSerialize spec](../simple-serialize.md#merkleization). +`def hash_tree_root(object: SSZSerializable) -> Hash` is a function for hashing objects into a single root utilizing a hash tree structure. `hash_tree_root` is defined in the [SimpleSerialize spec](../simple-serialize.md#merkleization). ### `signing_root` -`def signing_root(object: Container) -> Bytes32` is a function defined in the [SimpleSerialize spec](../simple-serialize.md#self-signed-containers) to compute signing messages. +`def signing_root(object: Container) -> Hash` is a function defined in the [SimpleSerialize spec](../simple-serialize.md#self-signed-containers) to compute signing messages. ### `bls_domain` @@ -758,7 +759,7 @@ def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot ```python def get_block_root_at_slot(state: BeaconState, - slot: Slot) -> Bytes32: + slot: Slot) -> Hash: """ Return the block root at a recent ``slot``. """ @@ -770,7 +771,7 @@ def get_block_root_at_slot(state: BeaconState, ```python def get_block_root(state: BeaconState, - epoch: Epoch) -> Bytes32: + epoch: Epoch) -> Hash: """ Return the block root at a recent ``epoch``. """ @@ -781,7 +782,7 @@ def get_block_root(state: BeaconState, ```python def get_randao_mix(state: BeaconState, - epoch: Epoch) -> Bytes32: + epoch: Epoch) -> Hash: """ Return the randao mix at a recent ``epoch``. ``epoch`` expected to be between (current_epoch - LATEST_RANDAO_MIXES_LENGTH, current_epoch]. @@ -793,7 +794,7 @@ def get_randao_mix(state: BeaconState, ```python def get_active_index_root(state: BeaconState, - epoch: Epoch) -> Bytes32: + epoch: Epoch) -> Hash: """ Return the index root at a recent ``epoch``. ``epoch`` expected to be between @@ -806,7 +807,7 @@ def get_active_index_root(state: BeaconState, ```python def generate_seed(state: BeaconState, - epoch: Epoch) -> Bytes32: + epoch: Epoch) -> Hash: """ Generate a seed for the given ``epoch``. """ @@ -844,7 +845,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: ### `verify_merkle_branch` ```python -def verify_merkle_branch(leaf: Bytes32, proof: List[Bytes32], depth: int, index: int, root: Bytes32) -> bool: +def verify_merkle_branch(leaf: Hash, proof: List[Hash], depth: int, index: int, root: Hash) -> bool: """ Verify that the given ``leaf`` is on the merkle branch ``proof`` starting with the given ``root``. @@ -861,7 +862,7 @@ def verify_merkle_branch(leaf: Bytes32, proof: List[Bytes32], depth: int, index: ### `get_shuffled_index` ```python -def get_shuffled_index(index: int, index_count: int, seed: Bytes32) -> ValidatorIndex: +def get_shuffled_index(index: int, index_count: int, seed: Hash) -> ValidatorIndex: """ Return the shuffled validator index corresponding to ``seed`` (and ``index_count``). """ @@ -885,7 +886,7 @@ def get_shuffled_index(index: int, index_count: int, seed: Bytes32) -> Validator ### `compute_committee` ```python -def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, count: int) -> List[ValidatorIndex]: +def compute_committee(indices: List[ValidatorIndex], seed: Hash, index: int, count: int) -> List[ValidatorIndex]: start = (len(indices) * index) // count end = (len(indices) * (index + 1)) // count return [indices[get_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)] From f4de5e3c72b1a178f55379a8fb6468d5f1a9eb52 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 18 Jun 2019 21:50:53 +0200 Subject: [PATCH 15/21] fix review comment: one line cache set --- scripts/build_spec.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index d672db419f..4890beaac9 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -85,8 +85,7 @@ def compute_committee(indices: List[ValidatorIndex], # type: ignore param_hash = (hash_tree_root(indices), seed, index, count) if param_hash not in committee_cache: - ret = _compute_committee(indices, seed, index, count) - committee_cache[param_hash] = ret + committee_cache[param_hash] = _compute_committee(indices, seed, index, count) return committee_cache[param_hash] From 207f632e1a4c609a3edd2724fc98f2fa341e94a6 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 18 Jun 2019 21:53:39 +0200 Subject: [PATCH 16/21] resolve other ret comment --- scripts/build_spec.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 4890beaac9..b7605df60b 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -91,13 +91,12 @@ def compute_committee(indices: List[ValidatorIndex], # type: ignore # Monkey patch hash cache _hash = hash -hash_cache: Dict[bytes, Bytes32] = {} +hash_cache: Dict[bytes, Hash] = {} def hash(x: bytes) -> Hash: if x not in hash_cache: - ret = _hash(x) - hash_cache[x] = Hash(ret) + hash_cache[x] = Hash(_hash(x)) return hash_cache[x] From f0e909c8d853b3db38dbe8bdef25c1f80a9e5b4c Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 18 Jun 2019 21:54:00 +0200 Subject: [PATCH 17/21] add mypy cache to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 16d39a4342..4dff5fbcb3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,9 @@ build/ output/ eth2.0-spec-tests/ + .pytest_cache +.mypy_cache # Dynamically built from Markdown spec test_libs/pyspec/eth2spec/phase0/spec.py From 346e61dfeb1d4924ec0921a91e99dc4450764041 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 18 Jun 2019 21:57:37 +0200 Subject: [PATCH 18/21] make epoch pattern similar to exit-epoch loop --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6534ce4f2d..8e81566340 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -704,11 +704,11 @@ def get_shard_delta(state: BeaconState, epoch: Epoch) -> int: ```python def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard: assert epoch <= get_current_epoch(state) + 1 - check_epoch = get_current_epoch(state) + 1 + check_epoch = Epoch(get_current_epoch(state) + 1) shard = Shard((state.start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT) while check_epoch > epoch: - check_epoch -= 1 - shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, Epoch(check_epoch))) % SHARD_COUNT) + check_epoch -= Epoch(1) + shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT) return shard ``` From 060041945cc25c95a8ec477800abc11dda21af11 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 18 Jun 2019 22:00:22 +0200 Subject: [PATCH 19/21] remove unnecessary cast --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8e81566340..3016b52d88 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -843,7 +843,7 @@ def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Hash) -> V position = max(index, flip) source = hash( seed + int_to_bytes(current_round, length=1) + - int_to_bytes(ValidatorIndex(position // 256), length=4) + int_to_bytes(position // 256, length=4) ) byte = source[(position % 256) // 8] bit = (byte >> (position % 8)) % 2 From 7d2f0a9dc0df1c69fc8178160325043b06cbb92c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 18 Jun 2019 14:07:05 -0600 Subject: [PATCH 20/21] clean up --- scripts/build_spec.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index b7605df60b..e209e2c56a 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -132,17 +132,11 @@ def objects_to_spec(functions: Dict[str, str], f" def __init__(self, _x: {value}) -> None:\n" f" ...\n" if value.startswith("uint") - # else "" - # else f"{key} = {value}\n" else f"class {key}({value}):\n pass\n" for key, value in custom_types.items() ] ) ) - # new_type_definitions += '\n'.join(['Bytes%s = BytesN[%s]' % (n, n) for n in byte_types]) - # new_type_definitions += '\n' + '\n'.join(['Hash = Bytes32', 'BLSPubkey = Bytes48', 'BLSSignature = Bytes96']) - # new_type_definitions += \ - # '\n' + '\n'.join(['''%s = NewType('%s', %s)''' % (key, key, value) for key, value in new_types.items()]) functions_spec = '\n\n'.join(functions.values()) constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants)) ssz_objects_instantiation_spec = '\n\n'.join(ssz_objects.values()) From 6df75ec3d479faf0eba764033e2d66822dba89f8 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 18 Jun 2019 22:16:21 +0200 Subject: [PATCH 21/21] cleanup unused byte part of builder --- scripts/build_spec.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index e209e2c56a..3a1b22efd3 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -120,7 +120,6 @@ def objects_to_spec(functions: Dict[str, str], ssz_objects: Dict[str, str], inserts: Dict[str, str], imports: Dict[str, str], - byte_types: List[int], ) -> str: """ Given all the objects that constitute a spec, combine them into a single pyfile. @@ -226,7 +225,7 @@ def combine_spec_objects(spec0: SpecObject, spec1: SpecObject) -> SpecObject: def build_phase0_spec(sourcefile: str, outfile: str=None) -> Optional[str]: functions, custom_types, constants, ssz_objects, inserts = get_spec(sourcefile) - spec = objects_to_spec(functions, custom_types, constants, ssz_objects, inserts, PHASE0_IMPORTS, BYTE_TYPES) + spec = objects_to_spec(functions, custom_types, constants, ssz_objects, inserts, PHASE0_IMPORTS) if outfile is not None: with open(outfile, 'w') as out: out.write(spec) @@ -243,7 +242,7 @@ def build_phase1_spec(phase0_sourcefile: str, spec_objects = phase0_spec for value in [phase1_custody, phase1_shard_data]: spec_objects = combine_spec_objects(spec_objects, value) - spec = objects_to_spec(*spec_objects, PHASE1_IMPORTS, BYTE_TYPES) + spec = objects_to_spec(*spec_objects, PHASE1_IMPORTS) if outfile is not None: with open(outfile, 'w') as out: out.write(spec)