From 565f61dfaa520708cc83a0a593e8eb2df9e5d516 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sun, 9 Jun 2019 20:41:21 +0100 Subject: [PATCH 01/25] Cleanup containers --- configs/constant_presets/mainnet.yaml | 6 +- configs/constant_presets/minimal.yaml | 6 +- scripts/build_spec.py | 11 +- specs/core/0_beacon-chain.md | 756 ++++++++---------- specs/core/0_deposit-contract.md | 6 +- specs/core/0_fork-choice.md | 12 +- specs/core/1_custody-game.md | 20 +- specs/core/1_shard-data-chains.md | 12 +- specs/light_client/sync_protocol.md | 8 +- specs/networking/rpc-interface.md | 8 +- specs/validator/0_beacon-chain-validator.md | 16 +- .../pyspec/eth2spec/test/helpers/block.py | 4 +- .../pyspec/eth2spec/test/helpers/deposits.py | 6 +- .../pyspec/eth2spec/test/helpers/genesis.py | 12 +- .../test/helpers/proposer_slashings.py | 2 +- .../pyspec/eth2spec/test/helpers/state.py | 2 +- .../pyspec/eth2spec/test/helpers/transfers.py | 2 +- .../test_process_attestation.py | 8 +- .../test_process_attester_slashing.py | 4 +- .../test_process_block_header.py | 2 +- .../block_processing/test_process_deposit.py | 28 +- .../test_process_proposer_slashing.py | 10 +- .../block_processing/test_process_transfer.py | 20 +- .../test_process_voluntary_exit.py | 34 +- .../test_process_crosslinks.py | 8 +- .../test_process_registry_updates.py | 26 +- ...est_process_early_derived_secret_reveal.py | 4 +- .../eth2spec/test/sanity/test_blocks.py | 46 +- 28 files changed, 515 insertions(+), 564 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index 6ac3f422f..d72b276c1 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -80,11 +80,11 @@ MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 # State list lengths # --------------------------------------------------------------- # 2**13 (= 8,192) epochs ~36 days -LATEST_RANDAO_MIXES_LENGTH: 8192 +RANDAO_MIXES_LENGTH: 8192 # 2**13 (= 8,192) epochs ~36 days -LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 8192 +ACTIVE_INDEX_ROOTS_LENGTH: 8192 # 2**13 (= 8,192) epochs ~36 days -LATEST_SLASHED_EXIT_LENGTH: 8192 +SLASHED_EXIT_LENGTH: 8192 # Reward and penalty quotients diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index 73448c3c6..25f1e8419 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -81,11 +81,11 @@ EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 4096 # State list lengths # --------------------------------------------------------------- # [customized] smaller state -LATEST_RANDAO_MIXES_LENGTH: 64 +RANDAO_MIXES_LENGTH: 64 # [customized] smaller state -LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 64 +ACTIVE_INDEX_ROOTS_LENGTH: 64 # [customized] smaller state -LATEST_SLASHED_EXIT_LENGTH: 64 +SLASHED_EXIT_LENGTH: 64 # Reward and penalty quotients diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 7a51970e3..e25147a7f 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -62,6 +62,7 @@ from eth2spec.utils.bls import ( from eth2spec.utils.hash_function import hash ''' +BYTE_TYPES = [4, 32, 48, 96] NEW_TYPES = { 'Slot': 'int', 'Epoch': 'int', @@ -69,7 +70,6 @@ NEW_TYPES = { 'ValidatorIndex': 'int', 'Gwei': 'int', } -BYTE_TYPES = [4, 32, 48, 96] SUNDRY_FUNCTIONS = ''' def get_ssz_type_by_name(name: str) -> Container: return globals()[name] @@ -130,9 +130,10 @@ 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(['Bytes%s = BytesN[%s]' % (n, n) for n in byte_types]) + 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()) @@ -177,7 +178,7 @@ def dependency_order_ssz_objects(objects: Dict[str, str]) -> None: items = list(objects.items()) for key, value in items: 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) + dependencies = map(lambda x: re.sub(r'\W|Vector|List|Container|Hash|BLSPubkey|BLSSignature|uint\d+|Bytes\d+|bytes', '', x), dependencies) for dep in dependencies: if dep in NEW_TYPES or len(dep) == 0: continue diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a6d9d23c5..9fd38d7db 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -20,7 +20,8 @@ - [Rewards and penalties](#rewards-and-penalties) - [Max operations per block](#max-operations-per-block) - [Signature domains](#signature-domains) - - [Data structures](#data-structures) + - [Custom types](#custom-types) + - [Containers](#containers) - [Misc dependencies](#misc-dependencies) - [`Fork`](#fork) - [`Validator`](#validator) @@ -45,7 +46,6 @@ - [`BeaconBlock`](#beaconblock) - [Beacon state](#beacon-state) - [`BeaconState`](#beaconstate) - - [Custom types](#custom-types) - [Helper functions](#helper-functions) - [`xor`](#xor) - [`hash`](#hash) @@ -216,9 +216,9 @@ These configurations are updated for releases, but may be out of sync during `de | Name | Value | Unit | Duration | | - | - | :-: | :-: | -| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | -| `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | -| `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | +| `RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | +| `ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | +| `SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | ### Rewards and penalties @@ -255,314 +255,6 @@ These configurations are updated for releases, but may be out of sync during `de | `DOMAIN_VOLUNTARY_EXIT` | `4` | | `DOMAIN_TRANSFER` | `5` | -## Data structures - -The following data structures are defined as [SimpleSerialize (SSZ)](../simple-serialize.md) objects. - -The types are defined topologically to aid in facilitating an executable version of the spec. - -### Misc dependencies - -#### `Fork` - -```python -class Fork(Container): - # Previous fork version - previous_version: Bytes4 - # Current fork version - current_version: Bytes4 - # Fork epoch number - epoch: uint64 -``` - -#### `Validator` - -```python -class Validator(Container): - # BLS public key - pubkey: Bytes48 - # Withdrawal credentials - withdrawal_credentials: Bytes32 - # Epoch when became eligible for activation - activation_eligibility_epoch: uint64 - # Epoch when validator activated - activation_epoch: uint64 - # Epoch when validator exited - exit_epoch: uint64 - # Epoch when validator is eligible to withdraw - withdrawable_epoch: uint64 - # Was the validator slashed - slashed: bool - # Effective balance - effective_balance: uint64 -``` - -#### `Crosslink` - -```python -class Crosslink(Container): - # Shard number - shard: uint64 - # Crosslinking data from epochs [start....end-1] - start_epoch: uint64 - end_epoch: uint64 - # Root of the previous crosslink - parent_root: Bytes32 - # Root of the crosslinked shard data since the previous crosslink - data_root: Bytes32 -``` - -#### `AttestationData` - -```python -class AttestationData(Container): - # LMD GHOST vote - beacon_block_root: Bytes32 - - # FFG vote - source_epoch: uint64 - source_root: Bytes32 - target_epoch: uint64 - target_root: Bytes32 - - # Crosslink vote - crosslink: Crosslink -``` - -#### `AttestationDataAndCustodyBit` - -```python -class AttestationDataAndCustodyBit(Container): - # Attestation data - data: AttestationData - # Custody bit - custody_bit: bool -``` - -#### `IndexedAttestation` - -```python -class IndexedAttestation(Container): - # Validator indices - custody_bit_0_indices: List[uint64] - custody_bit_1_indices: List[uint64] - # Attestation data - data: AttestationData - # Aggregate signature - signature: Bytes96 -``` - -#### `PendingAttestation` - -```python -class PendingAttestation(Container): - # Attester aggregation bitfield - aggregation_bitfield: bytes - # Attestation data - data: AttestationData - # Inclusion delay - inclusion_delay: uint64 - # Proposer index - proposer_index: uint64 -``` - -#### `Eth1Data` - -```python -class Eth1Data(Container): - # Root of the deposit tree - deposit_root: Bytes32 - # Total number of deposits - deposit_count: uint64 - # Block hash - block_hash: Bytes32 -``` - -#### `HistoricalBatch` - -```python -class HistoricalBatch(Container): - # Block roots - block_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] - # State roots - state_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] -``` - -#### `DepositData` - -```python -class DepositData(Container): - # BLS pubkey - pubkey: Bytes48 - # Withdrawal credentials - withdrawal_credentials: Bytes32 - # Amount in Gwei - amount: uint64 - # Container self-signature - signature: Bytes96 -``` - -#### `BeaconBlockHeader` - -```python -class BeaconBlockHeader(Container): - slot: uint64 - parent_root: Bytes32 - state_root: Bytes32 - body_root: Bytes32 - signature: Bytes96 -``` - -### Beacon operations - -#### `ProposerSlashing` - -```python -class ProposerSlashing(Container): - # Proposer index - proposer_index: uint64 - # First block header - header_1: BeaconBlockHeader - # Second block header - header_2: BeaconBlockHeader -``` - -#### `AttesterSlashing` - -```python -class AttesterSlashing(Container): - # First attestation - attestation_1: IndexedAttestation - # Second attestation - attestation_2: IndexedAttestation -``` - -#### `Attestation` - -```python -class Attestation(Container): - # Attester aggregation bitfield - aggregation_bitfield: bytes - # Attestation data - data: AttestationData - # Custody bitfield - custody_bitfield: bytes - # BLS aggregate signature - signature: Bytes96 -``` - -#### `Deposit` - -```python -class Deposit(Container): - # Branch in the deposit tree - proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH] - # Data - data: DepositData -``` - -#### `VoluntaryExit` - -```python -class VoluntaryExit(Container): - # Minimum epoch for processing exit - epoch: uint64 - # Index of the exiting validator - validator_index: uint64 - # Validator signature - signature: Bytes96 -``` - -#### `Transfer` - -```python -class Transfer(Container): - # Sender index - sender: uint64 - # Recipient index - recipient: uint64 - # Amount in Gwei - amount: uint64 - # Fee in Gwei for block proposer - fee: uint64 - # Inclusion slot - slot: uint64 - # Sender withdrawal pubkey - pubkey: Bytes48 - # Sender signature - signature: Bytes96 -``` - -### Beacon blocks - -#### `BeaconBlockBody` - -```python -class BeaconBlockBody(Container): - randao_reveal: Bytes96 - eth1_data: Eth1Data - graffiti: Bytes32 - proposer_slashings: List[ProposerSlashing] - attester_slashings: List[AttesterSlashing] - attestations: List[Attestation] - deposits: List[Deposit] - voluntary_exits: List[VoluntaryExit] - transfers: List[Transfer] -``` - -#### `BeaconBlock` - -```python -class BeaconBlock(Container): - # Header - slot: uint64 - parent_root: Bytes32 - state_root: Bytes32 - body: BeaconBlockBody - signature: Bytes96 -``` - -### Beacon state - -#### `BeaconState` - -```python -class BeaconState(Container): - # Misc - slot: uint64 - genesis_time: uint64 - fork: Fork # For versioning hard forks - # Validator registry - validator_registry: List[Validator] - balances: List[uint64] - # Randomness and committees - latest_randao_mixes: Vector[Bytes32, LATEST_RANDAO_MIXES_LENGTH] - latest_start_shard: uint64 - # Finality - previous_epoch_attestations: List[PendingAttestation] - current_epoch_attestations: List[PendingAttestation] - previous_justified_epoch: uint64 - current_justified_epoch: uint64 - previous_justified_root: Bytes32 - current_justified_root: Bytes32 - justification_bitfield: uint64 - finalized_epoch: uint64 - finalized_root: Bytes32 - # 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_slashed_balances: Vector[uint64, LATEST_SLASHED_EXIT_LENGTH] - latest_block_header: BeaconBlockHeader - historical_roots: List[Bytes32] - # Ethereum 1.0 chain data - latest_eth1_data: Eth1Data - eth1_data_votes: List[Eth1Data] - deposit_index: uint64 -``` - ## Custom types We define the following Python custom types for type hinting and readability: @@ -577,6 +269,264 @@ We define the following Python custom types for type hinting and readability: | `BLSPubkey` | `Bytes48` | a BLS12-381 public key | | `BLSSignature` | `Bytes96` | a BLS12-381 signature | +## Containers + +The following types are [SimpleSerialize (SSZ)](../simple-serialize.md) containers. + +*Note*: The definitions are ordered topologically to facilitate execution of the spec. + +### Misc dependencies + +#### `Fork` + +```python +class Fork(Container): + previous_version: Bytes4 + current_version: Bytes4 + epoch: Epoch +``` + +#### `Validator` + +```python +class Validator(Container): + pubkey: BLSPubkey + withdrawal_credentials: Hash + effective_balance: Gwei + slashed: bool + # Status epochs + activation_eligibility_epoch: Epoch + activation_epoch: Epoch + exit_epoch: Epoch + withdrawable_epoch: Epoch +``` + +#### `Crosslink` + +```python +class Crosslink(Container): + shard: Shard + parent_root: Hash + # Crosslinking data + start_epoch: Epoch + end_epoch: Epoch + data_root: Hash +``` + +#### `AttestationData` + +```python +class AttestationData(Container): + # LMD GHOST vote + beacon_block_root: Hash + # FFG vote + source_epoch: Epoch + source_root: Hash + target_epoch: Epoch + target_root: Hash + # Crosslink vote + crosslink: Crosslink +``` + +#### `AttestationDataAndCustodyBit` + +```python +class AttestationDataAndCustodyBit(Container): + data: AttestationData + custody_bit: bool +``` + +#### `IndexedAttestation` + +```python +class IndexedAttestation(Container): + custody_bit_0_indices: List[ValidatorIndex] # Indices with custody bit equal to 0 + custody_bit_1_indices: List[ValidatorIndex] # Indices with custody bit equal to 1 + data: AttestationData + signature: BLSSignature +``` + +#### `PendingAttestation` + +```python +class PendingAttestation(Container): + aggregation_bitfield: bytes + data: AttestationData + inclusion_delay: Slot + proposer_index: ValidatorIndex +``` + +#### `Eth1Data` + +```python +class Eth1Data(Container): + deposit_root: Hash + deposit_count: uint64 + block_hash: Hash +``` + +#### `HistoricalBatch` + +```python +class HistoricalBatch(Container): + block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] + state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] +``` + +#### `DepositData` + +```python +class DepositData(Container): + pubkey: BLSPubkey + withdrawal_credentials: Hash + amount: Gwei + signature: BLSSignature +``` + +#### `BeaconBlockHeader` + +```python +class BeaconBlockHeader(Container): + slot: Slot + parent_root: Hash + state_root: Hash + body_root: Hash + signature: BLSSignature +``` + +### Beacon operations + +#### `ProposerSlashing` + +```python +class ProposerSlashing(Container): + proposer_index: ValidatorIndex + header_1: BeaconBlockHeader + header_2: BeaconBlockHeader +``` + +#### `AttesterSlashing` + +```python +class AttesterSlashing(Container): + attestation_1: IndexedAttestation + attestation_2: IndexedAttestation +``` + +#### `Attestation` + +```python +class Attestation(Container): + aggregation_bitfield: bytes + data: AttestationData + custody_bitfield: bytes + signature: BLSSignature +``` + +#### `Deposit` + +```python +class Deposit(Container): + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] + data: DepositData +``` + +#### `VoluntaryExit` + +```python +class VoluntaryExit(Container): + epoch: Epoch + validator_index: ValidatorIndex + signature: BLSSignature +``` + +#### `Transfer` + +```python +class Transfer(Container): + sender: ValidatorIndex + recipient: ValidatorIndex + amount: Gwei + fee: Gwei + slot: Slot + pubkey: BLSPubkey + signature: BLSSignature +``` + +### Beacon blocks + +#### `BeaconBlockBody` + +```python +class BeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data + graffiti: Bytes32 + # Operations + proposer_slashings: List[ProposerSlashing] + attester_slashings: List[AttesterSlashing] + attestations: List[Attestation] + deposits: List[Deposit] + voluntary_exits: List[VoluntaryExit] + transfers: List[Transfer] +``` + +#### `BeaconBlock` + +```python +class BeaconBlock(Container): + slot: Slot + parent_root: Hash + state_root: Hash + body: BeaconBlockBody + signature: BLSSignature +``` + +### Beacon state + +#### `BeaconState` + +```python +class BeaconState(Container): + # Versioning + genesis_time: uint64 + slot: Slot + fork: Fork + # History + block_header: BeaconBlockHeader + block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] + state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] + historical_roots: List[Hash] + # Eth1 + eth1_data: Eth1Data + eth1_data_votes: List[Eth1Data] + eth1_deposit_index: uint64 + # Registry + validators: List[Validator] + balances: List[Gwei] + # Shuffling + start_shard: Shard + randao_mixes: Vector[Hash, RANDAO_MIXES_LENGTH] + active_index_roots: Vector[Hash, ACTIVE_INDEX_ROOTS_LENGTH] + # Slashings + slashed_balances: Vector[Gwei, SLASHED_EXIT_LENGTH] + # Attestations + previous_attestations: List[PendingAttestation] + current_attestations: List[PendingAttestation] + # Crosslinks + previous_crosslinks: Vector[Crosslink, SHARD_COUNT] + current_crosslinks: Vector[Crosslink, SHARD_COUNT] + # Justification + previous_justified_epoch: Epoch + previous_justified_root: Hash + current_justified_epoch: Epoch + current_justified_root: Hash + justification_bitfield: uint64 + # Finality + finalized_epoch: Epoch + finalized_root: Hash +``` + ## Helper functions *Note*: The definitions below are for specification purposes and are not necessarily optimal implementations. @@ -596,11 +546,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` @@ -681,7 +631,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 [i for i, v in enumerate(state.validators) if is_active_validator(v, epoch)] ``` ### `increase_balance` @@ -726,7 +676,7 @@ def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int: ```python def get_shard_delta(state: BeaconState, epoch: Epoch) -> int: """ - Return the number of shards to increment ``state.latest_start_shard`` during ``epoch``. + Return the number of shards to increment ``state.start_shard`` during ``epoch``. """ return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH) ``` @@ -737,7 +687,7 @@ 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 = (state.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 @@ -757,19 +707,19 @@ 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``. """ assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT - return state.latest_block_roots[slot % SLOTS_PER_HISTORICAL_ROOT] + return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT] ``` ### `get_block_root` ```python def get_block_root(state: BeaconState, - epoch: Epoch) -> Bytes32: + epoch: Epoch) -> Hash: """ Return the block root at a recent ``epoch``. """ @@ -780,37 +730,37 @@ 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]. + ``epoch`` expected to be between (current_epoch - RANDAO_MIXES_LENGTH, current_epoch]. """ - return state.latest_randao_mixes[epoch % LATEST_RANDAO_MIXES_LENGTH] + return state.randao_mixes[epoch % RANDAO_MIXES_LENGTH] ``` ### `get_active_index_root` ```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 - (current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY]. + (current_epoch - ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY]. """ - return state.latest_active_index_roots[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH] + return state.active_index_roots[epoch % ACTIVE_INDEX_ROOTS_LENGTH] ``` ### `generate_seed` ```python def generate_seed(state: BeaconState, - epoch: Epoch) -> Bytes32: + epoch: Epoch) -> Hash: """ 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 + RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD) + get_active_index_root(state, epoch) + int_to_bytes(epoch, length=32) ) @@ -834,7 +784,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: while True: candidate_index = first_committee[(epoch + i) % len(first_committee)] random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32] - effective_balance = state.validator_registry[candidate_index].effective_balance + effective_balance = state.validators[candidate_index].effective_balance if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: return candidate_index i += 1 @@ -843,7 +793,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``. @@ -860,7 +810,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: ValidatorIndex, index_count: int, seed: Hash) -> ValidatorIndex: """ Return the shuffled validator index corresponding to ``seed`` (and ``index_count``). """ @@ -884,7 +834,7 @@ def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Bytes32) - ### `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(i, len(indices), seed)] for i in range(start, end)] @@ -937,7 +887,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 max(sum([state.validators[index].effective_balance for index in indices]), 1) ``` ### `get_domain` @@ -1022,8 +972,8 @@ def validate_indexed_attestation(state: BeaconState, indexed_attestation: Indexe # Verify aggregate signature assert bls_verify_multiple( pubkeys=[ - bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_0_indices]), - bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_1_indices]), + bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_0_indices]), + bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_1_indices]), ], message_hashes=[ hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)), @@ -1112,14 +1062,14 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None: Initiate the exit of the validator of the given ``index``. """ # Return if validator already initiated exit - validator = state.validator_registry[index] + validator = state.validators[index] if validator.exit_epoch != FAR_FUTURE_EPOCH: return # Compute exit queue epoch - exit_epochs = [v.exit_epoch for v in state.validator_registry if v.exit_epoch != FAR_FUTURE_EPOCH] + exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH] 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]) + exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch]) if exit_queue_churn >= get_churn_limit(state): exit_queue_epoch += 1 @@ -1139,10 +1089,10 @@ 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 - slashed_balance = state.validator_registry[slashed_index].effective_balance - state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance + state.validators[slashed_index].slashed = True + state.validators[slashed_index].withdrawable_epoch = current_epoch + SLASHED_EXIT_LENGTH + slashed_balance = state.validators[slashed_index].effective_balance + state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH] += slashed_balance proposer_index = get_beacon_proposer_index(state) if whistleblower_index is None: @@ -1175,8 +1125,8 @@ Let `genesis_state = get_genesis_beacon_state(genesis_deposits, eth2genesis.gene def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis_eth1_data: Eth1Data) -> BeaconState: state = BeaconState( genesis_time=genesis_time, - latest_eth1_data=genesis_eth1_data, - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + eth1_data=genesis_eth1_data, + block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) # Process genesis deposits @@ -1184,15 +1134,15 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis process_deposit(state, deposit) # Process genesis activations - for validator in state.validator_registry: + for validator in state.validators: if validator.effective_balance >= MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH - # Populate latest_active_index_roots + # Populate active_index_roots genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH)) - for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH): - state.latest_active_index_roots[index] = genesis_active_index_root + for index in range(ACTIVE_INDEX_ROOTS_LENGTH): + state.active_index_roots[index] = genesis_active_index_root return state ``` @@ -1233,15 +1183,15 @@ def process_slots(state: BeaconState, slot: Slot) -> None: def process_slot(state: BeaconState) -> None: # Cache state root previous_state_root = hash_tree_root(state) - state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root + state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root # Cache latest block header state root - if state.latest_block_header.state_root == ZERO_HASH: - state.latest_block_header.state_root = previous_state_root + if state.block_header.state_root == ZERO_HASH: + state.block_header.state_root = previous_state_root # Cache block root - previous_block_root = signing_root(state.latest_block_header) - state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root + previous_block_root = signing_root(state.block_header) + state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root ``` ### Epoch processing @@ -1271,7 +1221,7 @@ def get_total_active_balance(state: BeaconState) -> Gwei: ```python def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: assert epoch in (get_current_epoch(state), get_previous_epoch(state)) - return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations + return state.current_attestations if epoch == get_current_epoch(state) else state.previous_attestations ``` ```python @@ -1296,7 +1246,7 @@ def get_unslashed_attesting_indices(state: BeaconState, output = set() 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))) + return sorted(filter(lambda index: not state.validators[index].slashed, list(output))) ``` ```python @@ -1391,7 +1341,7 @@ def process_crosslinks(state: BeaconState) -> None: ```python def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: total_balance = get_total_active_balance(state) - effective_balance = state.validator_registry[index].effective_balance + effective_balance = state.validators[index].effective_balance return effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH ``` @@ -1399,10 +1349,10 @@ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: 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 = [0 for _ in range(len(state.validators))] + penalties = [0 for _ in range(len(state.validators))] eligible_validator_indices = [ - index for index, v in enumerate(state.validator_registry) + index for index, v in enumerate(state.validators) if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch) ] @@ -1436,7 +1386,7 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: 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 + state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT ) return rewards, penalties @@ -1444,8 +1394,8 @@ 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 = [0 for index in range(len(state.validators))] + penalties = [0 for index in range(len(state.validators))] 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 @@ -1469,7 +1419,7 @@ 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)): + for i in range(len(state.validators)): increase_balance(state, i, rewards1[i] + rewards2[i]) decrease_balance(state, i, penalties1[i] + penalties2[i]) ``` @@ -1479,7 +1429,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None: ```python def process_registry_updates(state: BeaconState) -> None: # Process activation eligibility and ejections - for index, validator in enumerate(state.validator_registry): + for index, validator in enumerate(state.validators): if ( validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and validator.effective_balance >= MAX_EFFECTIVE_BALANCE @@ -1491,13 +1441,13 @@ def process_registry_updates(state: BeaconState) -> None: # Queue validators eligible for activation and not dequeued for activation prior to finalized epoch activation_queue = sorted([ - index for index, validator in enumerate(state.validator_registry) if + index for index, validator in enumerate(state.validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_epoch) - ], key=lambda index: state.validator_registry[index].activation_eligibility_epoch) + ], key=lambda index: state.validators[index].activation_eligibility_epoch) # Dequeued validators for activation up to churn limit (without resetting activation epoch) for index in activation_queue[:get_churn_limit(state)]: - validator = state.validator_registry[index] + validator = state.validators[index] if validator.activation_epoch == FAR_FUTURE_EPOCH: validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state)) ``` @@ -1510,12 +1460,12 @@ def process_slashings(state: BeaconState) -> None: total_balance = get_total_active_balance(state) # Compute slashed balances in the current epoch - total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH] - total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] + total_at_start = state.slashed_balances[(current_epoch + 1) % SLASHED_EXIT_LENGTH] + total_at_end = state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH] total_penalties = total_at_end - total_at_start - for index, validator in enumerate(state.validator_registry): - if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2: + for index, validator in enumerate(state.validators): + if validator.slashed and current_epoch == validator.withdrawable_epoch - SLASHED_EXIT_LENGTH // 2: penalty = max( validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT @@ -1533,34 +1483,34 @@ def process_final_updates(state: BeaconState) -> None: if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = [] # Update effective balances with hysteresis - for index, validator in enumerate(state.validator_registry): + for index, validator in enumerate(state.validators): balance = state.balances[index] HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2 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.start_shard = (state.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( + index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % ACTIVE_INDEX_ROOTS_LENGTH + state.active_index_roots[index_root_position] = hash_tree_root( get_active_validator_indices(state, next_epoch + ACTIVATION_EXIT_DELAY) ) # Set total slashed balances - state.latest_slashed_balances[next_epoch % LATEST_SLASHED_EXIT_LENGTH] = ( - state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] + state.slashed_balances[next_epoch % SLASHED_EXIT_LENGTH] = ( + state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH] ) # Set randao mix - state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch) + state.randao_mixes[next_epoch % RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch) # Set historical root accumulator if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: historical_batch = HistoricalBatch( - block_roots=state.latest_block_roots, - state_roots=state.latest_state_roots, + block_roots=state.block_roots, + state_roots=state.state_roots, ) state.historical_roots.append(hash_tree_root(historical_batch)) # Rotate current/previous epoch attestations - state.previous_epoch_attestations = state.current_epoch_attestations - state.current_epoch_attestations = [] + state.previous_attestations = state.current_attestations + state.current_attestations = [] ``` ### Block processing @@ -1580,15 +1530,15 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None: # Verify that the slots match assert block.slot == state.slot # Verify that the parent matches - assert block.parent_root == signing_root(state.latest_block_header) + assert block.parent_root == signing_root(state.block_header) # Save current block as the new latest block - state.latest_block_header = BeaconBlockHeader( + state.block_header = BeaconBlockHeader( slot=block.slot, parent_root=block.parent_root, body_root=hash_tree_root(block.body), ) # Verify proposer is not slashed - proposer = state.validator_registry[get_beacon_proposer_index(state)] + proposer = state.validators[get_beacon_proposer_index(state)] assert not proposer.slashed # Verify proposer signature assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER)) @@ -1598,7 +1548,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None: ```python def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: - proposer = state.validator_registry[get_beacon_proposer_index(state)] + proposer = state.validators[get_beacon_proposer_index(state)] # Verify that the provided randao value is valid assert bls_verify( proposer.pubkey, @@ -1607,7 +1557,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: get_domain(state, DOMAIN_RANDAO), ) # Mix it in - state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = ( + state.randao_mixes[get_current_epoch(state) % RANDAO_MIXES_LENGTH] = ( xor(get_randao_mix(state, get_current_epoch(state)), hash(body.randao_reveal)) ) @@ -1619,7 +1569,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None: state.eth1_data_votes.append(body.eth1_data) if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD: - state.latest_eth1_data = body.eth1_data + state.eth1_data = body.eth1_data ``` #### Operations @@ -1627,7 +1577,7 @@ def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None: ```python def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: # Verify that outstanding deposits are processed up to the maximum number of deposits - assert len(body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index) + assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) # Verify that there are no duplicate transfers assert len(body.transfers) == len(set(body.transfers)) @@ -1651,7 +1601,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla """ Process ``ProposerSlashing`` operation. """ - proposer = state.validator_registry[proposer_slashing.proposer_index] + proposer = state.validators[proposer_slashing.proposer_index] # Verify that the epoch is the same assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot) # But the headers are different @@ -1683,7 +1633,7 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla attesting_indices_1 = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices attesting_indices_2 = attestation_2.custody_bit_0_indices + attestation_2.custody_bit_1_indices for index in sorted(set(attesting_indices_1).intersection(attesting_indices_2)): - if is_slashable_validator(state.validator_registry[index], get_current_epoch(state)): + if is_slashable_validator(state.validators[index], get_current_epoch(state)): slash_validator(state, index) slashed_any = True assert slashed_any @@ -1711,11 +1661,11 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: if data.target_epoch == get_current_epoch(state): ffg_data = (state.current_justified_epoch, state.current_justified_root, get_current_epoch(state)) parent_crosslink = state.current_crosslinks[data.crosslink.shard] - state.current_epoch_attestations.append(pending_attestation) + state.current_attestations.append(pending_attestation) else: ffg_data = (state.previous_justified_epoch, state.previous_justified_root, get_previous_epoch(state)) parent_crosslink = state.previous_crosslinks[data.crosslink.shard] - state.previous_epoch_attestations.append(pending_attestation) + state.previous_attestations.append(pending_attestation) # Check FFG data, crosslink data, and signature assert ffg_data == (data.source_epoch, data.source_root, data.target_epoch) @@ -1738,16 +1688,16 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: leaf=hash_tree_root(deposit.data), proof=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH, - index=state.deposit_index, - root=state.latest_eth1_data.deposit_root, + index=state.eth1_deposit_index, + root=state.eth1_data.deposit_root, ) # Deposits must be processed in order - state.deposit_index += 1 + state.eth1_deposit_index += 1 pubkey = deposit.data.pubkey amount = deposit.data.amount - validator_pubkeys = [v.pubkey for v in state.validator_registry] + validator_pubkeys = [v.pubkey for v in state.validators] if pubkey not in validator_pubkeys: # Verify the deposit signature (proof of possession). # Invalid signatures are allowed by the deposit contract, @@ -1759,7 +1709,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: return # Add validator and balance entries - state.validator_registry.append(Validator( + state.validators.append(Validator( pubkey=pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, activation_eligibility_epoch=FAR_FUTURE_EPOCH, @@ -1782,7 +1732,7 @@ def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None: """ Process ``VoluntaryExit`` operation. """ - validator = state.validator_registry[exit.validator_index] + validator = state.validators[exit.validator_index] # Verify the validator is active assert is_active_validator(validator, get_current_epoch(state)) # Verify the validator has not yet exited @@ -1811,13 +1761,13 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None: assert state.slot == transfer.slot # Sender must be not yet eligible for activation, withdrawn, or transfer balance over MAX_EFFECTIVE_BALANCE assert ( - state.validator_registry[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or - get_current_epoch(state) >= state.validator_registry[transfer.sender].withdrawable_epoch or + state.validators[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or + get_current_epoch(state) >= state.validators[transfer.sender].withdrawable_epoch or transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender] ) # Verify that the pubkey is valid assert ( - state.validator_registry[transfer.sender].withdrawal_credentials == + state.validators[transfer.sender].withdrawal_credentials == int_to_bytes(BLS_WITHDRAWAL_PREFIX, length=1) + hash(transfer.pubkey)[1:] ) # Verify that the signature is valid diff --git a/specs/core/0_deposit-contract.md b/specs/core/0_deposit-contract.md index e80dad1c5..d40553f43 100644 --- a/specs/core/0_deposit-contract.md +++ b/specs/core/0_deposit-contract.md @@ -75,9 +75,9 @@ Every Ethereum 1.0 deposit, of size at least `MIN_DEPOSIT_AMOUNT`, emits a `Depo When `CHAIN_START_FULL_DEPOSIT_THRESHOLD` of full deposits have been made, the deposit contract emits the `Eth2Genesis` log. The beacon chain state may then be initialized by calling the `get_genesis_beacon_state` function (defined [here](./0_beacon-chain.md#genesis-state)) where: * `genesis_time` equals `time` in the `Eth2Genesis` log -* `latest_eth1_data.deposit_root` equals `deposit_root` in the `Eth2Genesis` log -* `latest_eth1_data.deposit_count` equals `deposit_count` in the `Eth2Genesis` log -* `latest_eth1_data.block_hash` equals the hash of the block that included the log +* `eth1_data.deposit_root` equals `deposit_root` in the `Eth2Genesis` log +* `eth1_data.deposit_count` equals `deposit_count` in the `Eth2Genesis` log +* `eth1_data.block_hash` equals the hash of the block that included the log * `genesis_validator_deposits` is a list of `Deposit` objects built according to the `Deposit` logs up to the deposit that triggered the `Eth2Genesis` log, processed in the order in which they were emitted (oldest to newest) ## Vyper code diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index 91c3e27ee..739c06d59 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -39,7 +39,7 @@ All terminology, constants, functions, and protocol mechanics defined in the [Ph Processing the beacon chain is similar to processing the Ethereum 1.0 chain. Clients download and process blocks and maintain a view of what is the current "canonical chain", terminating at the current "head". For a beacon block, `block`, to be processed by a node, the following conditions must be met: * The parent block with root `block.parent_root` has been processed and accepted. -* An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted. +* An Ethereum 1.0 block pointed to by the `state.eth1_data.block_hash` has been processed and accepted. * The node's Unix time is greater than or equal to `state.genesis_time + block.slot * SECONDS_PER_SLOT`. *Note*: Leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year. @@ -68,8 +68,8 @@ def get_ancestor(store: Store, block: BeaconBlock, slot: Slot) -> BeaconBlock: return get_ancestor(store, store.get_parent(block), slot) ``` -* Let `get_latest_attestation(store: Store, index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `index`. If several such attestations exist, use the one the validator `v` observed first. -* Let `get_latest_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, index)`. +* Let `get_attestation(store: Store, index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `index`. If several such attestations exist, use the one the validator `v` observed first. +* Let `get_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_attestation(store, index)`. * Let `get_children(store: Store, block: BeaconBlock) -> List[BeaconBlock]` return the child blocks of the given `block`. * Let `justified_head_state` be the resulting `BeaconState` object from processing the chain up to the `justified_head`. * The `head` is `lmd_ghost(store, justified_head_state, justified_head)` where the function `lmd_ghost` is defined below. Note that the implementation below is suboptimal; there are implementations that compute the head in time logarithmic in slot count. @@ -79,16 +79,16 @@ def lmd_ghost(store: Store, start_state: BeaconState, start_block: BeaconBlock) """ Execute the LMD-GHOST algorithm to find the head ``BeaconBlock``. """ - validators = start_state.validator_registry + validators = start_state.validators active_validator_indices = get_active_validator_indices(validators, slot_to_epoch(start_state.slot)) - attestation_targets = [(i, get_latest_attestation_target(store, i)) for i in active_validator_indices] + attestation_targets = [(i, get_attestation_target(store, i)) for i in active_validator_indices] # Use the rounded-balance-with-hysteresis supplied by the protocol for fork # choice voting. This reduces the number of recomputations that need to be # made for optimized implementations that precompute and save data def get_vote_count(block: BeaconBlock) -> int: return sum( - start_state.validator_registry[validator_index].effective_balance + start_state.validators[validator_index].effective_balance for validator_index, target in attestation_targets if get_ancestor(store, target, block.slot) == block ) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 6c89ef853..75ab36609 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -339,7 +339,7 @@ def process_custody_key_reveal(state: BeaconState, Note that this function mutates ``state``. """ - revealer = state.validator_registry[reveal.revealer_index] + revealer = state.validators[reveal.revealer_index] epoch_to_sign = get_randao_epoch_for_custody_period(revealer.next_custody_reveal_period, reveal.revealed_index) assert revealer.next_custody_reveal_period < get_validators_custody_reveal_period(state, reveal.revealed_index) @@ -389,8 +389,8 @@ def process_early_derived_secret_reveal(state: BeaconState, Note that this function mutates ``state``. """ - revealed_validator = state.validator_registry[reveal.revealed_index] - masker = state.validator_registry[reveal.masker_index] + revealed_validator = state.validators[reveal.revealed_index] + masker = state.validators[reveal.masker_index] derived_secret_location = reveal.epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS assert reveal.epoch >= get_current_epoch(state) + RANDAO_PENALTY_EPOCHS @@ -399,7 +399,7 @@ def process_early_derived_secret_reveal(state: BeaconState, assert reveal.revealed_index not in state.exposed_derived_secrets[derived_secret_location] # Verify signature correctness - masker = state.validator_registry[reveal.masker_index] + masker = state.validators[reveal.masker_index] pubkeys = [revealed_validator.pubkey, masker.pubkey] message_hashes = [ hash_tree_root(reveal.epoch), @@ -465,7 +465,7 @@ def process_chunk_challenge(state: BeaconState, validate_indexed_attestation(state, convert_to_indexed(state, challenge.attestation)) # Verify it is not too late to challenge assert slot_to_epoch(challenge.attestation.data.slot) >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY - responder = state.validator_registry[challenge.responder_index] + responder = state.validators[challenge.responder_index] assert responder.exit_epoch >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY # Verify the responder participated in the attestation attesters = get_attesting_indices(state, challenge.attestation.data, challenge.attestation.aggregation_bitfield) @@ -507,7 +507,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> None: # Verify challenge signature - challenger = state.validator_registry[challenge.challenger_index] + challenger = state.validators[challenge.challenger_index] assert bls_verify( pubkey=challenger.pubkey, message_hash=signing_root(challenge), @@ -520,7 +520,7 @@ def process_bit_challenge(state: BeaconState, attestation = challenge.attestation validate_indexed_attestation(state, convert_to_indexed(state, attestation)) # Verify the attestation is eligible for challenging - responder = state.validator_registry[challenge.responder_index] + responder = state.validators[challenge.responder_index] assert (slot_to_epoch(attestation.data.slot) + responder.max_reveal_lateness <= get_validators_custody_reveal_period(state, challenge.responder_index)) @@ -630,7 +630,7 @@ def process_bit_challenge_response(state: BeaconState, # Verify chunk index assert response.chunk_index < challenge.chunk_count # Verify responder has not been slashed - responder = state.validator_registry[challenge.responder_index] + responder = state.validators[challenge.responder_index] assert not responder.slashed # Verify the chunk matches the crosslink data root assert verify_merkle_branch( @@ -669,7 +669,7 @@ Run `process_reveal_deadlines(state)` immediately after `process_registry_update process_reveal_deadlines(state) # end insert @process_reveal_deadlines def process_reveal_deadlines(state: BeaconState) -> None: - for index, validator in enumerate(state.validator_registry): + for index, validator in enumerate(state.validators): 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) @@ -710,7 +710,7 @@ def after_process_final_updates(state: BeaconState) -> None: validator_indices_in_records = set( [record.challenger_index for record in records] + [record.responder_index for record in records] ) - for index, validator in enumerate(state.validator_registry): + for index, validator in enumerate(state.validators): 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 diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 21e08e7c9..a895b3c38 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -158,9 +158,9 @@ def get_persistent_committee(state: BeaconState, later_start_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.validators, 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.validators, later_start_epoch)) // (SHARD_COUNT * TARGET_COMMITTEE_SIZE), ) + 1 @@ -190,7 +190,7 @@ def get_shard_proposer_index(state: BeaconState, # Search for an active proposer for index in persistent_committee: - if is_active_validator(state.validator_registry[index], get_current_epoch(state)): + if is_active_validator(state.validators[index], get_current_epoch(state)): return index # No block can be proposed if no validator is active @@ -224,7 +224,7 @@ def verify_shard_attestation_signature(state: BeaconState, pubkeys = [] for i, index in enumerate(persistent_committee): if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b1: - validator = state.validator_registry[index] + validator = state.validators[index] assert is_active_validator(validator, get_current_epoch(state)) pubkeys.append(validator.pubkey) assert bls_verify( @@ -325,7 +325,7 @@ def is_valid_shard_block(beacon_blocks: List[BeaconBlock], proposer_index = get_shard_proposer_index(beacon_state, candidate.shard, candidate.slot) assert proposer_index is not None assert bls_verify( - pubkey=beacon_state.validator_registry[proposer_index].pubkey, + pubkey=beacon_state.validators[proposer_index].pubkey, message_hash=signing_root(block), signature=candidate.signature, domain=get_domain(beacon_state, slot_to_epoch(candidate.slot), DOMAIN_SHARD_PROPOSER), @@ -395,7 +395,7 @@ def is_valid_beacon_attestation(shard: Shard, assert candidate.data.previous_attestation.epoch < slot_to_epoch(candidate.data.slot) # Check crosslink data root - start_epoch = beacon_state.latest_crosslinks[shard].epoch + start_epoch = beacon_state.crosslinks[shard].epoch end_epoch = min(slot_to_epoch(candidate.data.slot) - CROSSLINK_LOOKBACK, start_epoch + MAX_EPOCHS_PER_CROSSLINK) blocks = [] for slot in range(start_epoch * SLOTS_PER_EPOCH, end_epoch * SLOTS_PER_EPOCH): diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 8501c5869..eb4bf09eb 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -31,7 +31,7 @@ We define an "expansion" of an object as an object where a field in an object th We define two expansions: -* `ExtendedBeaconState`, which is identical to a `BeaconState` except `latest_active_index_roots: List[Bytes32]` is replaced by `latest_active_indices: List[List[ValidatorIndex]]`, where `BeaconState.latest_active_index_roots[i] = hash_tree_root(ExtendedBeaconState.latest_active_indices[i])`. +* `ExtendedBeaconState`, which is identical to a `BeaconState` except `active_index_roots: List[Bytes32]` is replaced by `active_indices: List[List[ValidatorIndex]]`, where `BeaconState.active_index_roots[i] = hash_tree_root(ExtendedBeaconState.active_indices[i])`. * `ExtendedBeaconBlock`, which is identical to a `BeaconBlock` except `state_root` is replaced with the corresponding `state: ExtendedBeaconState`. ### `get_active_validator_indices` @@ -40,10 +40,10 @@ Note that there is now a new way to compute `get_active_validator_indices`: ```python def get_active_validator_indices(state: ExtendedBeaconState, epoch: Epoch) -> List[ValidatorIndex]: - return state.latest_active_indices[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH] + return state.active_indices[epoch % ACTIVE_INDEX_ROOTS_LENGTH] ``` -Note that it takes `state` instead of `state.validator_registry` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments. +Note that it takes `state` instead of `state.validators` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments. ### `MerklePartial` @@ -85,7 +85,7 @@ def get_period_data(block: ExtendedBeaconBlock, shard_id: Shard, later: bool) -> return PeriodData( validator_count, generate_seed(block.state, period_start), - [block.state.validator_registry[i] for i in indices], + [block.state.validators[i] for i in indices], ) ``` diff --git a/specs/networking/rpc-interface.md b/specs/networking/rpc-interface.md index b81f78408..be154075c 100644 --- a/specs/networking/rpc-interface.md +++ b/specs/networking/rpc-interface.md @@ -95,8 +95,8 @@ Since some clients are waiting for `libp2p` implementations in their respective ( network_id: uint8 chain_id: uint64 - latest_finalized_root: bytes32 - latest_finalized_epoch: uint64 + finalized_root: bytes32 + finalized_epoch: uint64 best_root: bytes32 best_slot: uint64 ) @@ -107,7 +107,7 @@ Clients exchange `hello` messages upon connection, forming a two-phase handshake Clients SHOULD immediately disconnect from one another following the handshake above under the following conditions: 1. If `network_id` belongs to a different chain, since the client definitionally cannot sync with this client. -2. If the `latest_finalized_root` shared by the peer is not in the client's chain at the expected epoch. For example, if Peer 1 in the diagram below has `(root, epoch)` of `(A, 5)` and Peer 2 has `(B, 3)`, Peer 1 would disconnect because it knows that `B` is not the root in their chain at epoch 3: +2. If the `finalized_root` shared by the peer is not in the client's chain at the expected epoch. For example, if Peer 1 in the diagram below has `(root, epoch)` of `(A, 5)` and Peer 2 has `(B, 3)`, Peer 1 would disconnect because it knows that `B` is not the root in their chain at epoch 3: ``` Root A @@ -136,7 +136,7 @@ Root B ^ +---+ ``` -Once the handshake completes, the client with the higher `latest_finalized_epoch` or `best_slot` (if the clients have equal `latest_finalized_epoch`s) SHOULD request beacon block roots from its counterparty via `beacon_block_roots` (i.e. RPC method `10`). +Once the handshake completes, the client with the higher `finalized_epoch` or `best_slot` (if the clients have equal `finalized_epoch`s) SHOULD request beacon block roots from its counterparty via `beacon_block_roots` (i.e. RPC method `10`). ### Goodbye diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 2f5aa4264..d062e1d3b 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -101,15 +101,15 @@ To submit a deposit: * Let `signature` be the result of `bls_sign` of the `signing_root(deposit_data)` with `domain=bls_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `bls_domain` will default to zeroes there). * Send a transaction on the Ethereum 1.0 chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96])` along with a deposit of `amount` Gwei. -*Note*: Deposits made for the same `pubkey` are treated as for the same validator. A singular `Validator` will be added to `state.validator_registry` with each additional deposit amount added to the validator's balance. A validator can only be activated when total deposits for the validator pubkey meet or exceed `MAX_EFFECTIVE_BALANCE`. +*Note*: Deposits made for the same `pubkey` are treated as for the same validator. A singular `Validator` will be added to `state.validators` with each additional deposit amount added to the validator's balance. A validator can only be activated when total deposits for the validator pubkey meet or exceed `MAX_EFFECTIVE_BALANCE`. ### Process deposit -Deposits cannot be processed into the beacon chain until the Eth 1.0 block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes _a minimum_ of `ETH1_FOLLOW_DISTANCE` Eth 1.0 blocks (~4 hours) plus `ETH1_DATA_VOTING_PERIOD` epochs (~1.7 hours). Once the requisite Eth 1.0 data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validator_registry` within an epoch or two. The validator is then in a queue to be activated. +Deposits cannot be processed into the beacon chain until the Eth 1.0 block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes _a minimum_ of `ETH1_FOLLOW_DISTANCE` Eth 1.0 blocks (~4 hours) plus `ETH1_DATA_VOTING_PERIOD` epochs (~1.7 hours). Once the requisite Eth 1.0 data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validators` within an epoch or two. The validator is then in a queue to be activated. ### Validator index -Once a validator has been processed and added to the beacon state's `validator_registry`, the validator's `validator_index` is defined by the index into the registry at which the [`ValidatorRecord`](../core/0_beacon-chain.md#validator) contains the `pubkey` specified in the validator's deposit. A validator's `validator_index` is guaranteed to not change from the time of initial deposit until the validator exits and fully withdraws. This `validator_index` is used throughout the specification to dictate validator roles and responsibilities at any point and should be stored locally. +Once a validator has been processed and added to the beacon state's `validators`, the validator's `validator_index` is defined by the index into the registry at which the [`ValidatorRecord`](../core/0_beacon-chain.md#validator) contains the `pubkey` specified in the validator's deposit. A validator's `validator_index` is guaranteed to not change from the time of initial deposit until the validator exits and fully withdraws. This `validator_index` is used throughout the specification to dictate validator roles and responsibilities at any point and should be stored locally. ### Activation @@ -118,7 +118,7 @@ In normal operation, the validator is quickly activated at which point the valid The function [`is_active_validator`](../core/0_beacon-chain.md#is_active_validator) can be used to check if a validator is active during a given epoch. Usage is as follows: ```python -validator = state.validator_registry[validator_index] +validator = state.validators[validator_index] is_active = is_active_validator(validator, get_current_epoch(state)) ``` @@ -221,10 +221,10 @@ epoch_signature = bls_sign( ##### Eth1 Data -`block.eth1_data` is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed, `state.latest_eth1_data` is updated, and validator deposits up to this root can be processed. The deposit root can be calculated by calling the `get_deposit_root()` function of the deposit contract using the post-state of the block hash. +`block.eth1_data` is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed, `state.eth1_data` is updated, and validator deposits up to this root can be processed. The deposit root can be calculated by calling the `get_deposit_root()` function of the deposit contract using the post-state of the block hash. * Let `D` be the list of `Eth1DataVote` objects `vote` in `state.eth1_data_votes` where: - * `vote.eth1_data.block_hash` is the hash of an Eth 1.0 block that is (i) part of the canonical chain, (ii) >= `ETH1_FOLLOW_DISTANCE` blocks behind the head, and (iii) newer than `state.latest_eth1_data.block_hash`. + * `vote.eth1_data.block_hash` is the hash of an Eth 1.0 block that is (i) part of the canonical chain, (ii) >= `ETH1_FOLLOW_DISTANCE` blocks behind the head, and (iii) newer than `state.eth1_data.block_hash`. * `vote.eth1_data.deposit_count` is the deposit count of the Eth 1.0 deposit contract at the block defined by `vote.eth1_data.block_hash`. * `vote.eth1_data.deposit_root` is the deposit root of the Eth 1.0 deposit contract at the block defined by `vote.eth1_data.block_hash`. * If `D` is empty: @@ -267,9 +267,9 @@ Up to `MAX_ATTESTATIONS` aggregate attestations can be included in the `block`. ##### Deposits -If there are any unprocessed deposits for the existing `state.latest_eth1_data` (i.e. `state.latest_eth1_data.deposit_count > state.deposit_index`), then pending deposits _must_ be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`. These [`deposits`](../core/0_beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [Eth 1.0 deposit contract](../core/0_deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](../core/0_beacon-chain.md#deposits). +If there are any unprocessed deposits for the existing `state.eth1_data` (i.e. `state.eth1_data.deposit_count > state.eth1_deposit_index`), then pending deposits _must_ be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, eth1_data.deposit_count - state.eth1_deposit_index)`. These [`deposits`](../core/0_beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [Eth 1.0 deposit contract](../core/0_deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](../core/0_beacon-chain.md#deposits). -The `proof` for each deposit must be constructed against the deposit root contained in `state.latest_eth1_data` rather than the deposit root at the time the deposit was initially logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `latest_eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation. +The `proof` for each deposit must be constructed against the deposit root contained in `state.eth1_data` rather than the deposit root at the time the deposit was initially logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation. ##### Voluntary exits diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index 5c7cb02a0..ebd20f1b5 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -57,8 +57,8 @@ def build_empty_block(spec, state, slot=None, signed=False): slot = state.slot empty_block = spec.BeaconBlock() empty_block.slot = slot - empty_block.body.eth1_data.deposit_count = state.deposit_index - previous_block_header = deepcopy(state.latest_block_header) + empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index + previous_block_header = deepcopy(state.block_header) if previous_block_header.state_root == spec.ZERO_HASH: previous_block_header.state_root = state.hash_tree_root() empty_block.parent_root = signing_root(previous_block_header) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index c85d265eb..e3bd839aa 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -58,7 +58,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c """ Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount. """ - pre_validator_count = len(state.validator_registry) + pre_validator_count = len(state.validators) # fill previous deposits with zero-hash deposit_data_leaves = [spec.ZERO_HASH] * pre_validator_count @@ -80,6 +80,6 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c signed ) - state.latest_eth1_data.deposit_root = root - state.latest_eth1_data.deposit_count = len(deposit_data_leaves) + state.eth1_data.deposit_root = root + state.eth1_data.deposit_count = len(deposit_data_leaves) return deposit diff --git a/test_libs/pyspec/eth2spec/test/helpers/genesis.py b/test_libs/pyspec/eth2spec/test/helpers/genesis.py index 83af56621..241706957 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/genesis.py +++ b/test_libs/pyspec/eth2spec/test/helpers/genesis.py @@ -22,8 +22,8 @@ def create_genesis_state(spec, num_validators): state = spec.BeaconState( genesis_time=0, - deposit_index=num_validators, - latest_eth1_data=spec.Eth1Data( + eth1_deposit_index=num_validators, + eth1_data=spec.Eth1Data( deposit_root=deposit_root, deposit_count=num_validators, block_hash=spec.ZERO_HASH, @@ -32,16 +32,16 @@ def create_genesis_state(spec, num_validators): # We "hack" in the initial validators, # as it is much faster than creating and processing genesis deposits for every single test case. state.balances = [spec.MAX_EFFECTIVE_BALANCE] * num_validators - state.validator_registry = [build_mock_validator(spec, i, state.balances[i]) for i in range(num_validators)] + state.validators = [build_mock_validator(spec, i, state.balances[i]) for i in range(num_validators)] # Process genesis activations - for validator in state.validator_registry: + for validator in state.validators: if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = spec.GENESIS_EPOCH validator.activation_epoch = spec.GENESIS_EPOCH genesis_active_index_root = hash_tree_root(spec.get_active_validator_indices(state, spec.GENESIS_EPOCH)) - for index in range(spec.LATEST_ACTIVE_INDEX_ROOTS_LENGTH): - state.latest_active_index_roots[index] = genesis_active_index_root + for index in range(spec.ACTIVE_INDEX_ROOTS_LENGTH): + state.active_index_roots[index] = genesis_active_index_root return state diff --git a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py index 86c6acf47..d5b7f7b7f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py +++ b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py @@ -7,7 +7,7 @@ from eth2spec.test.helpers.keys import pubkey_to_privkey def get_valid_proposer_slashing(spec, state, signed_1=False, signed_2=False): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[-1] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] slot = state.slot header_1 = spec.BeaconBlockHeader( diff --git a/test_libs/pyspec/eth2spec/test/helpers/state.py b/test_libs/pyspec/eth2spec/test/helpers/state.py index 63aa27d70..19a04b04f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/state.py +++ b/test_libs/pyspec/eth2spec/test/helpers/state.py @@ -22,4 +22,4 @@ def get_state_root(spec, state, slot) -> bytes: Return the state root at a recent ``slot``. """ assert slot < state.slot <= slot + spec.SLOTS_PER_HISTORICAL_ROOT - return state.latest_state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT] + return state.state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT] diff --git a/test_libs/pyspec/eth2spec/test/helpers/transfers.py b/test_libs/pyspec/eth2spec/test/helpers/transfers.py index e619c5569..f7397ca38 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/transfers.py +++ b/test_libs/pyspec/eth2spec/test/helpers/transfers.py @@ -31,7 +31,7 @@ def get_valid_transfer(spec, state, slot=None, sender_index=None, amount=None, f sign_transfer(spec, state, transfer, transfer_privkey) # ensure withdrawal_credentials reproducible - state.validator_registry[transfer.sender].withdrawal_credentials = ( + state.validators[transfer.sender].withdrawal_credentials = ( spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:] ) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index 2b34ab405..6cd2d1194 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -31,17 +31,17 @@ def run_attestation_processing(spec, state, attestation, valid=True): yield 'post', None return - current_epoch_count = len(state.current_epoch_attestations) - previous_epoch_count = len(state.previous_epoch_attestations) + current_epoch_count = len(state.current_attestations) + previous_epoch_count = len(state.previous_attestations) # process attestation spec.process_attestation(state, attestation) # Make sure the attestation has been processed if attestation.data.target_epoch == spec.get_current_epoch(state): - assert len(state.current_epoch_attestations) == current_epoch_count + 1 + assert len(state.current_attestations) == current_epoch_count + 1 else: - assert len(state.previous_epoch_attestations) == previous_epoch_count + 1 + assert len(state.previous_attestations) == previous_epoch_count + 1 # yield post-state yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py index 6c7637d59..c51f5a8a9 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py @@ -34,7 +34,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True) # Process slashing spec.process_attester_slashing(state, attester_slashing) - slashed_validator = state.validator_registry[slashed_index] + slashed_validator = state.validators[slashed_index] # Check slashing assert slashed_validator.slashed @@ -135,7 +135,7 @@ def test_participants_already_slashed(spec, state): attestation_1 = attester_slashing.attestation_1 validator_indices = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices for index in validator_indices: - state.validator_registry[index].slashed = True + state.validators[index].slashed = True yield from run_attester_slashing_processing(spec, state, attester_slashing, False) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_block_header.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_block_header.py index f3c017982..a2306ef4d 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_block_header.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_block_header.py @@ -78,7 +78,7 @@ def test_proposer_slashed(spec, state): proposer_index = spec.get_beacon_proposer_index(stub_state) # set proposer to slashed - state.validator_registry[proposer_index].slashed = True + state.validators[proposer_index].slashed = True block = build_empty_block_for_next_slot(spec, state, signed=True) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index c50b11f2e..7efb57871 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -16,7 +16,7 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef - post-state ('post'). If ``valid == False``, run expecting ``AssertionError`` """ - pre_validator_count = len(state.validator_registry) + pre_validator_count = len(state.validators) pre_balance = 0 if validator_index < pre_validator_count: pre_balance = get_balance(state, validator_index) @@ -34,29 +34,29 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef yield 'post', state if not effective: - assert len(state.validator_registry) == pre_validator_count + assert len(state.validators) == pre_validator_count assert len(state.balances) == pre_validator_count if validator_index < pre_validator_count: assert get_balance(state, validator_index) == pre_balance else: if validator_index < pre_validator_count: # top-up - assert len(state.validator_registry) == pre_validator_count + assert len(state.validators) == pre_validator_count assert len(state.balances) == pre_validator_count else: # new validator - assert len(state.validator_registry) == pre_validator_count + 1 + assert len(state.validators) == pre_validator_count + 1 assert len(state.balances) == pre_validator_count + 1 assert get_balance(state, validator_index) == pre_balance + deposit.data.amount - assert state.deposit_index == state.latest_eth1_data.deposit_count + assert state.eth1_deposit_index == state.eth1_data.deposit_count @with_all_phases @spec_state_test def test_new_deposit(spec, state): # fresh deposit = next validator index = validator appended to registry - validator_index = len(state.validator_registry) + validator_index = len(state.validators) amount = spec.MAX_EFFECTIVE_BALANCE deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) @@ -68,7 +68,7 @@ def test_new_deposit(spec, state): @spec_state_test def test_invalid_sig_new_deposit(spec, state): # fresh deposit = next validator index = validator appended to registry - validator_index = len(state.validator_registry) + validator_index = len(state.validators) amount = spec.MAX_EFFECTIVE_BALANCE deposit = prepare_state_and_deposit(spec, state, validator_index, amount) yield from run_deposit_processing(spec, state, deposit, validator_index, valid=True, effective=False) @@ -117,12 +117,12 @@ def test_invalid_withdrawal_credentials_top_up(spec, state): @with_all_phases @spec_state_test def test_wrong_index(spec, state): - validator_index = len(state.validator_registry) + validator_index = len(state.validators) amount = spec.MAX_EFFECTIVE_BALANCE deposit = prepare_state_and_deposit(spec, state, validator_index, amount) - # mess up deposit_index - deposit.index = state.deposit_index + 1 + # mess up eth1_deposit_index + deposit.index = state.eth1_deposit_index + 1 sign_deposit_data(spec, state, deposit.data, privkeys[validator_index]) @@ -132,7 +132,7 @@ def test_wrong_index(spec, state): @with_all_phases @spec_state_test def test_wrong_deposit_for_deposit_count(spec, state): - deposit_data_leaves = [spec.ZERO_HASH] * len(state.validator_registry) + deposit_data_leaves = [spec.ZERO_HASH] * len(state.validators) # build root for deposit_1 index_1 = len(deposit_data_leaves) @@ -166,8 +166,8 @@ def test_wrong_deposit_for_deposit_count(spec, state): ) # state has root for deposit_2 but is at deposit_count for deposit_1 - state.latest_eth1_data.deposit_root = root_2 - state.latest_eth1_data.deposit_count = deposit_count_1 + state.eth1_data.deposit_root = root_2 + state.eth1_data.deposit_count = deposit_count_1 yield from run_deposit_processing(spec, state, deposit_2, index_2, valid=False) @@ -178,7 +178,7 @@ def test_wrong_deposit_for_deposit_count(spec, state): @with_all_phases @spec_state_test def test_bad_merkle_proof(spec, state): - validator_index = len(state.validator_registry) + validator_index = len(state.validators) amount = spec.MAX_EFFECTIVE_BALANCE deposit = prepare_state_and_deposit(spec, state, validator_index, amount) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py index b35241859..af34ea709 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py @@ -28,7 +28,7 @@ def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True) yield 'post', state # check if slashed - slashed_validator = state.validator_registry[proposer_slashing.proposer_index] + slashed_validator = state.validators[proposer_slashing.proposer_index] assert slashed_validator.slashed assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH @@ -77,7 +77,7 @@ def test_invalid_sig_1_and_2(spec, state): def test_invalid_proposer_index(spec, state): proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) # Index just too high (by 1) - proposer_slashing.proposer_index = len(state.validator_registry) + proposer_slashing.proposer_index = len(state.validators) yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False) @@ -111,7 +111,7 @@ def test_proposer_is_not_activated(spec, state): proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) # set proposer to be not active yet - state.validator_registry[proposer_slashing.proposer_index].activation_epoch = spec.get_current_epoch(state) + 1 + state.validators[proposer_slashing.proposer_index].activation_epoch = spec.get_current_epoch(state) + 1 yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False) @@ -122,7 +122,7 @@ def test_proposer_is_slashed(spec, state): proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) # set proposer to slashed - state.validator_registry[proposer_slashing.proposer_index].slashed = True + state.validators[proposer_slashing.proposer_index].slashed = True yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False) @@ -137,6 +137,6 @@ def test_proposer_is_withdrawn(spec, state): # set proposer withdrawable_epoch in past current_epoch = spec.get_current_epoch(state) proposer_index = proposer_slashing.proposer_index - state.validator_registry[proposer_index].withdrawable_epoch = current_epoch - 1 + state.validators[proposer_index].withdrawable_epoch = current_epoch - 1 yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py index 1294ca84a..e9d282b3a 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py @@ -41,7 +41,7 @@ def run_transfer_processing(spec, state, transfer, valid=True): def test_success_non_activated(spec, state): transfer = get_valid_transfer(spec, state, signed=True) # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer) @@ -55,7 +55,7 @@ def test_success_withdrawable(spec, state): transfer = get_valid_transfer(spec, state, signed=True) # withdrawable_epoch in past so can transfer - state.validator_registry[transfer.sender].withdrawable_epoch = spec.get_current_epoch(state) - 1 + state.validators[transfer.sender].withdrawable_epoch = spec.get_current_epoch(state) - 1 yield from run_transfer_processing(spec, state, transfer) @@ -86,7 +86,7 @@ def test_success_active_above_max_effective_fee(spec, state): def test_invalid_signature(spec, state): transfer = get_valid_transfer(spec, state) # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -107,7 +107,7 @@ def test_active_but_transfer_past_effective_balance(spec, state): def test_incorrect_slot(spec, state): transfer = get_valid_transfer(spec, state, slot=state.slot + 1, signed=True) # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -120,7 +120,7 @@ def test_insufficient_balance_for_fee(spec, state): transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=0, fee=1, signed=True) # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -133,7 +133,7 @@ def test_insufficient_balance(spec, state): transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0, signed=True) # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -153,7 +153,7 @@ def test_no_dust_sender(spec, state): ) # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -167,7 +167,7 @@ def test_no_dust_recipient(spec, state): state.balances[transfer.recipient] = 0 # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -176,9 +176,9 @@ def test_no_dust_recipient(spec, state): @spec_state_test def test_invalid_pubkey(spec, state): transfer = get_valid_transfer(spec, state, signed=True) - state.validator_registry[transfer.sender].withdrawal_credentials = spec.ZERO_HASH + state.validators[transfer.sender].withdrawal_credentials = spec.ZERO_HASH # un-activate so validator can transfer - state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_voluntary_exit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_voluntary_exit.py index 3359c5e78..33cacc4e2 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_voluntary_exit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_voluntary_exit.py @@ -21,14 +21,14 @@ def run_voluntary_exit_processing(spec, state, voluntary_exit, valid=True): yield 'post', None return - pre_exit_epoch = state.validator_registry[validator_index].exit_epoch + pre_exit_epoch = state.validators[validator_index].exit_epoch spec.process_voluntary_exit(state, voluntary_exit) yield 'post', state assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH - assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH + assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH @with_all_phases @@ -39,7 +39,7 @@ def test_success(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] voluntary_exit = build_voluntary_exit(spec, state, current_epoch, validator_index, privkey, signed=True) @@ -55,7 +55,7 @@ def test_invalid_signature(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] voluntary_exit = build_voluntary_exit(spec, state, current_epoch, validator_index, privkey) @@ -76,7 +76,7 @@ def test_success_exit_queue(spec, state): # Prepare a bunch of exits, based on the current state exit_queue = [] for index in initial_indices: - privkey = pubkey_to_privkey[state.validator_registry[index].pubkey] + privkey = pubkey_to_privkey[state.validators[index].pubkey] exit_queue.append(build_voluntary_exit( spec, state, @@ -94,7 +94,7 @@ def test_success_exit_queue(spec, state): # exit an additional validator validator_index = spec.get_active_validator_indices(state, current_epoch)[-1] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] voluntary_exit = build_voluntary_exit( spec, state, @@ -109,8 +109,8 @@ def test_success_exit_queue(spec, state): yield from run_voluntary_exit_processing(spec, state, voluntary_exit) assert ( - state.validator_registry[validator_index].exit_epoch == - state.validator_registry[initial_indices[0]].exit_epoch + 1 + state.validators[validator_index].exit_epoch == + state.validators[initial_indices[0]].exit_epoch + 1 ) @@ -122,7 +122,7 @@ def test_validator_exit_in_future(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] voluntary_exit = build_voluntary_exit( spec, @@ -146,7 +146,7 @@ def test_validator_invalid_validator_index(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] voluntary_exit = build_voluntary_exit( spec, @@ -156,7 +156,7 @@ def test_validator_invalid_validator_index(spec, state): privkey, signed=False, ) - voluntary_exit.validator_index = len(state.validator_registry) + voluntary_exit.validator_index = len(state.validators) sign_voluntary_exit(spec, state, voluntary_exit, privkey) yield from run_voluntary_exit_processing(spec, state, voluntary_exit, False) @@ -167,9 +167,9 @@ def test_validator_invalid_validator_index(spec, state): def test_validator_not_active(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] - state.validator_registry[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH # build and test voluntary exit voluntary_exit = build_voluntary_exit( @@ -192,10 +192,10 @@ def test_validator_already_exited(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] # but validator already has exited - state.validator_registry[validator_index].exit_epoch = current_epoch + 2 + state.validators[validator_index].exit_epoch = current_epoch + 2 voluntary_exit = build_voluntary_exit( spec, @@ -214,7 +214,7 @@ def test_validator_already_exited(spec, state): def test_validator_not_active_long_enough(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] - privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + privkey = pubkey_to_privkey[state.validators[validator_index].pubkey] voluntary_exit = build_voluntary_exit( spec, @@ -226,7 +226,7 @@ def test_validator_not_active_long_enough(spec, state): ) assert ( - current_epoch - state.validator_registry[validator_index].activation_epoch < + current_epoch - state.validators[validator_index].activation_epoch < spec.PERSISTENT_COMMITTEE_PERIOD ) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index 65d958678..cd4532457 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -56,7 +56,7 @@ def test_single_crosslink_update_from_current_epoch(spec, state): fill_aggregate_attestation(spec, state, attestation) add_attestation_to_state(spec, state, attestation, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY) - assert len(state.current_epoch_attestations) == 1 + assert len(state.current_attestations) == 1 shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) @@ -77,7 +77,7 @@ def test_single_crosslink_update_from_previous_epoch(spec, state): fill_aggregate_attestation(spec, state, attestation) add_attestation_to_state(spec, state, attestation, state.slot + spec.SLOTS_PER_EPOCH) - assert len(state.previous_epoch_attestations) == 1 + assert len(state.previous_attestations) == 1 shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) @@ -130,8 +130,8 @@ def test_double_late_crosslink(spec, state): next_epoch(spec, state) add_attestation_to_state(spec, state, attestation_2, state.slot + 1) - assert len(state.previous_epoch_attestations) == 1 - assert len(state.current_epoch_attestations) == 0 + assert len(state.previous_attestations) == 1 + assert len(state.current_attestations) == 0 crosslink_deltas = spec.get_crosslink_deltas(state) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index e6679f844..6863af3b1 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -35,23 +35,23 @@ def run_process_registry_updates(spec, state, valid=True): @spec_state_test def test_activation(spec, state): index = 0 - assert spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state)) + assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) # Mock a new deposit - state.validator_registry[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH - state.validator_registry[index].activation_epoch = spec.FAR_FUTURE_EPOCH - state.validator_registry[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE - assert not spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state)) + state.validators[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE + assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): next_epoch(spec, state) yield from run_process_registry_updates(spec, state) - assert state.validator_registry[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH - assert state.validator_registry[index].activation_epoch != spec.FAR_FUTURE_EPOCH + assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH + assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH assert spec.is_active_validator( - state.validator_registry[index], + state.validators[index], spec.get_current_epoch(state), ) @@ -60,19 +60,19 @@ def test_activation(spec, state): @spec_state_test def test_ejection(spec, state): index = 0 - assert spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state)) - assert state.validator_registry[index].exit_epoch == spec.FAR_FUTURE_EPOCH + assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + assert state.validators[index].exit_epoch == spec.FAR_FUTURE_EPOCH # Mock an ejection - state.validator_registry[index].effective_balance = spec.EJECTION_BALANCE + state.validators[index].effective_balance = spec.EJECTION_BALANCE for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): next_epoch(spec, state) yield from run_process_registry_updates(spec, state) - assert state.validator_registry[index].exit_epoch != spec.FAR_FUTURE_EPOCH + assert state.validators[index].exit_epoch != spec.FAR_FUTURE_EPOCH assert not spec.is_active_validator( - state.validator_registry[index], + state.validators[index], spec.get_current_epoch(state), ) diff --git a/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_early_derived_secret_reveal.py b/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_early_derived_secret_reveal.py index 110231d77..87297d443 100644 --- a/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_early_derived_secret_reveal.py +++ b/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_early_derived_secret_reveal.py @@ -24,7 +24,7 @@ def run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, v spec.process_early_derived_secret_reveal(state, randao_key_reveal) - slashed_validator = state.validator_registry[randao_key_reveal.revealed_index] + slashed_validator = state.validators[randao_key_reveal.revealed_index] if randao_key_reveal.epoch >= spec.get_current_epoch(state) + spec.CUSTODY_PERIOD_TO_RANDAO_PADDING: assert slashed_validator.slashed @@ -111,7 +111,7 @@ def test_double_reveal(spec, state): @spec_state_test def test_revealer_is_slashed(spec, state): randao_key_reveal = get_valid_early_derived_secret_reveal(spec, state, spec.get_current_epoch(state)) - state.validator_registry[randao_key_reveal.revealed_index].slashed = True + state.validators[randao_key_reveal.revealed_index].slashed = True yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 587c37742..a5079b901 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -91,7 +91,7 @@ def test_empty_epoch_transition(spec, state): # assert state.slot == block.slot # assert state.finalized_epoch < spec.get_current_epoch(state) - 4 -# for index in range(len(state.validator_registry)): +# for index in range(len(state.validators)): # assert get_balance(state, index) < get_balance(pre_state, index) @@ -103,7 +103,7 @@ def test_proposer_slashing(spec, state): proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) validator_index = proposer_slashing.proposer_index - assert not state.validator_registry[validator_index].slashed + assert not state.validators[validator_index].slashed yield 'pre', state @@ -119,7 +119,7 @@ def test_proposer_slashing(spec, state): yield 'post', state # check if slashed - slashed_validator = state.validator_registry[validator_index] + slashed_validator = state.validators[validator_index] assert slashed_validator.slashed assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH @@ -137,7 +137,7 @@ def test_attester_slashing(spec, state): validator_index = (attester_slashing.attestation_1.custody_bit_0_indices + attester_slashing.attestation_1.custody_bit_1_indices)[0] - assert not state.validator_registry[validator_index].slashed + assert not state.validators[validator_index].slashed yield 'pre', state @@ -152,7 +152,7 @@ def test_attester_slashing(spec, state): spec.state_transition(state, block) yield 'post', state - slashed_validator = state.validator_registry[validator_index] + slashed_validator = state.validators[validator_index] assert slashed_validator.slashed assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH @@ -172,10 +172,10 @@ def test_attester_slashing(spec, state): @with_all_phases @spec_state_test def test_deposit_in_block(spec, state): - initial_registry_len = len(state.validator_registry) + initial_registry_len = len(state.validators) initial_balances_len = len(state.balances) - validator_index = len(state.validator_registry) + validator_index = len(state.validators) amount = spec.MAX_EFFECTIVE_BALANCE deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) @@ -190,10 +190,10 @@ def test_deposit_in_block(spec, state): spec.state_transition(state, block) yield 'post', state - assert len(state.validator_registry) == initial_registry_len + 1 + assert len(state.validators) == initial_registry_len + 1 assert len(state.balances) == initial_balances_len + 1 assert get_balance(state, validator_index) == spec.MAX_EFFECTIVE_BALANCE - assert state.validator_registry[validator_index].pubkey == pubkeys[validator_index] + assert state.validators[validator_index].pubkey == pubkeys[validator_index] @with_all_phases @@ -203,7 +203,7 @@ def test_deposit_top_up(spec, state): amount = spec.MAX_EFFECTIVE_BALANCE // 4 deposit = prepare_state_and_deposit(spec, state, validator_index, amount) - initial_registry_len = len(state.validator_registry) + initial_registry_len = len(state.validators) initial_balances_len = len(state.balances) validator_pre_balance = get_balance(state, validator_index) @@ -218,7 +218,7 @@ def test_deposit_top_up(spec, state): spec.state_transition(state, block) yield 'post', state - assert len(state.validator_registry) == initial_registry_len + assert len(state.validators) == initial_registry_len assert len(state.balances) == initial_balances_len assert get_balance(state, validator_index) == validator_pre_balance + amount @@ -233,17 +233,17 @@ def test_attestation(spec, state): attestation = get_valid_attestation(spec, state, signed=True) # Add to state via block transition - pre_current_attestations_len = len(state.current_epoch_attestations) + pre_current_attestations_len = len(state.current_attestations) attestation_block = build_empty_block_for_next_slot(spec, state) attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY attestation_block.body.attestations.append(attestation) sign_block(spec, state, attestation_block) spec.state_transition(state, attestation_block) - assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1 + assert len(state.current_attestations) == pre_current_attestations_len + 1 - # Epoch transition should move to previous_epoch_attestations - pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations) + # Epoch transition should move to previous_attestations + pre_current_attestations_root = spec.hash_tree_root(state.current_attestations) epoch_block = build_empty_block_for_next_slot(spec, state) epoch_block.slot += spec.SLOTS_PER_EPOCH @@ -253,8 +253,8 @@ def test_attestation(spec, state): yield 'blocks', [attestation_block, epoch_block], List[spec.BeaconBlock] yield 'post', state - assert len(state.current_epoch_attestations) == 0 - assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root + assert len(state.current_attestations) == 0 + assert spec.hash_tree_root(state.previous_attestations) == pre_current_attestations_root @with_all_phases @@ -289,7 +289,7 @@ def test_voluntary_exit(spec, state): sign_block(spec, state, initiate_exit_block) spec.state_transition(state, initiate_exit_block) - assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH + assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH # Process within epoch transition exit_block = build_empty_block_for_next_slot(spec, state) @@ -300,7 +300,7 @@ def test_voluntary_exit(spec, state): yield 'blocks', [initiate_exit_block, exit_block], List[spec.BeaconBlock] yield 'post', state - assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH + assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH @with_all_phases @@ -317,7 +317,7 @@ def test_transfer(spec, state): pre_transfer_recipient_balance = get_balance(state, recipient_index) # un-activate so validator can transfer - state.validator_registry[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + state.validators[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield 'pre', state @@ -343,10 +343,10 @@ def test_balance_driven_status_transitions(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[-1] - assert state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH + assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold - state.validator_registry[validator_index].effective_balance = spec.EJECTION_BALANCE + state.validators[validator_index].effective_balance = spec.EJECTION_BALANCE yield 'pre', state @@ -359,7 +359,7 @@ def test_balance_driven_status_transitions(spec, state): yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state - assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH + assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH @with_all_phases From 36a6c1bf1f56266c763ab5a20922c46cfebd5013 Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 9 Jun 2019 21:30:42 +0100 Subject: [PATCH 02/25] Set MIN_ATTESTATION_INCLUSION_DELAY to 1 See item 7 of #1054. We should consider increasing the slot duration as well. --- 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 a6d9d23c5..6f273de4b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -199,7 +199,7 @@ These configurations are updated for releases, but may be out of sync during `de | Name | Value | Unit | Duration | | - | - | :-: | :-: | -| `MIN_ATTESTATION_INCLUSION_DELAY` | `2**2` (= 4) | slots | 24 seconds | +| `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 6 seconds | | `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes | | `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes | | `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes | From 05a35c7228f0ae12c44e46cb1d202c6989af434e Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 10 Jun 2019 15:14:32 +0100 Subject: [PATCH 03/25] Tweak inclusion delay rewards and set BASE_REWARD_FACTOR Substantive changes: 1) Split the inclusion delay reward between attester and proposer to add up to at most one base reward. This is analogous to the reward logic in `slash_validator`, and makes the `BASE_REWARDS_PER_EPOCH` constant include proposer rewards. 2) Double `BASE_REWARD_FACTOR` to 2^6 (addressing item 4 in #1054). When the total effective balance is 2^17 ETH then maximum annual issuance is a bit below 2^21 ETH. Maximum annual issuance happens when a) all validators make perfect attestations (matching source, target, head, as well as consistent crosslink data), b) all attestations are included as fast as possible (in particular, no skip blocks), and c) there are no slashings. ```python BASE_REWARD_FACTOR = 2**6 SLOTS_PER_EPOCH = 2**6 SECONDS_PER_SLOT = 6 BASE_REWARDS_PER_EPOCH = 5 GWEI_PER_ETH = 10**9 MAX_TOTAL_EFFECTIVE_BALANCE = 2**27 * GWEI_PER_ETH TARGET_MAX_ISSUANCE = 2**21 * GWEI_PER_ETH def integer_squareroot(n: int) -> int: """ The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``. """ assert n >= 0 x = n y = (x + 1) // 2 while y < x: x = y y = (x + n // x) // 2 return x MAX_REWARDS_PER_EPOCH = MAX_TOTAL_EFFECTIVE_BALANCE * BASE_REWARD_FACTOR // integer_squareroot(MAX_TOTAL_EFFECTIVE_BALANCE) // BASE_REWARDS_PER_EPOCH EPOCHS_PER_YEAR = 365.25*24*60*60 / (SECONDS_PER_SLOT * SLOTS_PER_EPOCH) MAX_REWARDS_PER_YEAR = EPOCHS_PER_YEAR * MAX_REWARDS_PER_EPOCH * BASE_REWARDS_PER_EPOCH print(MAX_REWARDS_PER_YEAR / TARGET_MAX_ISSUANCE) ``` --- specs/core/0_beacon-chain.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a6d9d23c5..8a60b6f34 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -224,14 +224,13 @@ These configurations are updated for releases, but may be out of sync during `de | Name | Value | | - | - | -| `BASE_REWARD_FACTOR` | `2**5` (= 32) | +| `BASE_REWARD_FACTOR` | `2**6` (= 64) | | `WHISTLEBLOWING_REWARD_QUOTIENT` | `2**9` (= 512) | | `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) | | `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) | | `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) | -* **The `BASE_REWARD_FACTOR` is NOT final. Once all other protocol details are finalized, it will be adjusted to target a theoretical maximum total issuance of `2**21` ETH per year if `2**27` ETH is validating (and therefore `2**20` per year if `2**25` ETH is validating, etc.)** -* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (~18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` epochs it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`. +* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (about 18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` epochs it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`. ### Max operations per block @@ -1425,8 +1424,10 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: 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 + proposer_reward = get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT + rewards[attestation.proposer_index] += proposer_reward + max_attester_reward = get_base_reward(state, index) - proposer_reward + rewards[index] += max_attester_reward * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay # Inactivity penalty finality_delay = previous_epoch - state.finalized_epoch From dc56d87eef3a367783e57723cf8be060f3de7926 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Mon, 10 Jun 2019 21:16:51 +0100 Subject: [PATCH 04/25] Revert a couple of renamings --- specs/core/0_beacon-chain.md | 28 +++++++++---------- specs/test_formats/operations/README.md | 6 ++-- test_generators/operations/main.py | 4 +-- .../pyspec/eth2spec/test/helpers/block.py | 2 +- .../test/helpers/proposer_slashings.py | 2 +- .../test_process_attestation.py | 8 +++--- .../test_process_proposer_slashing.py | 2 +- .../test_process_crosslinks.py | 8 +++--- .../eth2spec/test/sanity/test_blocks.py | 12 ++++---- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9fd38d7db..013d002c9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -493,7 +493,7 @@ class BeaconState(Container): slot: Slot fork: Fork # History - block_header: BeaconBlockHeader + parent_block_header: BeaconBlockHeader block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] historical_roots: List[Hash] @@ -511,8 +511,8 @@ class BeaconState(Container): # Slashings slashed_balances: Vector[Gwei, SLASHED_EXIT_LENGTH] # Attestations - previous_attestations: List[PendingAttestation] - current_attestations: List[PendingAttestation] + previous_epoch_attestations: List[PendingAttestation] + current_epoch_attestations: List[PendingAttestation] # Crosslinks previous_crosslinks: Vector[Crosslink, SHARD_COUNT] current_crosslinks: Vector[Crosslink, SHARD_COUNT] @@ -1126,7 +1126,7 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis state = BeaconState( genesis_time=genesis_time, eth1_data=genesis_eth1_data, - block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + parent_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) # Process genesis deposits @@ -1186,11 +1186,11 @@ def process_slot(state: BeaconState) -> None: state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root # Cache latest block header state root - if state.block_header.state_root == ZERO_HASH: - state.block_header.state_root = previous_state_root + if state.parent_block_header.state_root == ZERO_HASH: + state.parent_block_header.state_root = previous_state_root # Cache block root - previous_block_root = signing_root(state.block_header) + previous_block_root = signing_root(state.parent_block_header) state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root ``` @@ -1221,7 +1221,7 @@ def get_total_active_balance(state: BeaconState) -> Gwei: ```python def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: assert epoch in (get_current_epoch(state), get_previous_epoch(state)) - return state.current_attestations if epoch == get_current_epoch(state) else state.previous_attestations + return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations ``` ```python @@ -1509,8 +1509,8 @@ def process_final_updates(state: BeaconState) -> None: ) state.historical_roots.append(hash_tree_root(historical_batch)) # Rotate current/previous epoch attestations - state.previous_attestations = state.current_attestations - state.current_attestations = [] + state.previous_epoch_attestations = state.current_epoch_attestations + state.current_epoch_attestations = [] ``` ### Block processing @@ -1530,9 +1530,9 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None: # Verify that the slots match assert block.slot == state.slot # Verify that the parent matches - assert block.parent_root == signing_root(state.block_header) + assert block.parent_root == signing_root(state.parent_block_header) # Save current block as the new latest block - state.block_header = BeaconBlockHeader( + state.parent_block_header = BeaconBlockHeader( slot=block.slot, parent_root=block.parent_root, body_root=hash_tree_root(block.body), @@ -1661,11 +1661,11 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: if data.target_epoch == get_current_epoch(state): ffg_data = (state.current_justified_epoch, state.current_justified_root, get_current_epoch(state)) parent_crosslink = state.current_crosslinks[data.crosslink.shard] - state.current_attestations.append(pending_attestation) + state.current_epoch_attestations.append(pending_attestation) else: ffg_data = (state.previous_justified_epoch, state.previous_justified_root, get_previous_epoch(state)) parent_crosslink = state.previous_crosslinks[data.crosslink.shard] - state.previous_attestations.append(pending_attestation) + state.previous_epoch_attestations.append(pending_attestation) # Check FFG data, crosslink data, and signature assert ffg_data == (data.source_epoch, data.source_root, data.target_epoch) diff --git a/specs/test_formats/operations/README.md b/specs/test_formats/operations/README.md index 32cf880b3..dead3722b 100644 --- a/specs/test_formats/operations/README.md +++ b/specs/test_formats/operations/README.md @@ -14,7 +14,7 @@ post: BeaconState -- state after applying the operation. No ## Condition -A handler of the `operations` test-runner should process these cases, +A handler of the `operations` test-runner should process these cases, calling the corresponding processing implementation. Operations: @@ -23,13 +23,13 @@ Operations: |-------------------------|----------------------|----------------------|--------------------------------------------------------| | `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` | | `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` | -| `block_header` | `Block` | `block` | `process_block_header(state, block)` | +| `parent_block_header` | `Block` | `block` | `process_block_header(state, block)` | | `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` | | `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` | | `transfer` | `Transfer` | `transfer` | `process_transfer(state, transfer)` | | `voluntary_exit` | `VoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` | -Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here. +Note that `parent_block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here. The resulting state should match the expected `post` state, or if the `post` state is left blank, the handler should reject the input operation as invalid. diff --git a/test_generators/operations/main.py b/test_generators/operations/main.py index 82e05b307..70089ebe8 100644 --- a/test_generators/operations/main.py +++ b/test_generators/operations/main.py @@ -42,8 +42,8 @@ if __name__ == "__main__": create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation)), create_suite('attester_slashing', 'minimal', lambda: generate_from_tests(test_process_attester_slashing)), create_suite('attester_slashing', 'mainnet', lambda: generate_from_tests(test_process_attester_slashing)), - create_suite('block_header', 'minimal', lambda: generate_from_tests(test_process_block_header)), - create_suite('block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header)), + create_suite('parent_block_header', 'minimal', lambda: generate_from_tests(test_process_block_header)), + create_suite('parent_block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header)), create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit)), create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit)), create_suite('proposer_slashing', 'minimal', lambda: generate_from_tests(test_process_proposer_slashing)), diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index ebd20f1b5..03f8d5b7e 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -58,7 +58,7 @@ def build_empty_block(spec, state, slot=None, signed=False): empty_block = spec.BeaconBlock() empty_block.slot = slot empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index - previous_block_header = deepcopy(state.block_header) + previous_block_header = deepcopy(state.parent_block_header) if previous_block_header.state_root == spec.ZERO_HASH: previous_block_header.state_root = state.hash_tree_root() empty_block.parent_root = signing_root(previous_block_header) diff --git a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py index d5b7f7b7f..d725f3316 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py +++ b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py @@ -1,6 +1,6 @@ from copy import deepcopy -from eth2spec.test.helpers.block_header import sign_block_header +from eth2spec.test.helpers.parent_block_header import sign_block_header from eth2spec.test.helpers.keys import pubkey_to_privkey diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index 6cd2d1194..2b34ab405 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -31,17 +31,17 @@ def run_attestation_processing(spec, state, attestation, valid=True): yield 'post', None return - current_epoch_count = len(state.current_attestations) - previous_epoch_count = len(state.previous_attestations) + current_epoch_count = len(state.current_epoch_attestations) + previous_epoch_count = len(state.previous_epoch_attestations) # process attestation spec.process_attestation(state, attestation) # Make sure the attestation has been processed if attestation.data.target_epoch == spec.get_current_epoch(state): - assert len(state.current_attestations) == current_epoch_count + 1 + assert len(state.current_epoch_attestations) == current_epoch_count + 1 else: - assert len(state.previous_attestations) == previous_epoch_count + 1 + assert len(state.previous_epoch_attestations) == previous_epoch_count + 1 # yield post-state yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py index af34ea709..41039ab06 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py @@ -1,5 +1,5 @@ from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases -from eth2spec.test.helpers.block_header import sign_block_header +from eth2spec.test.helpers.parent_block_header import sign_block_header from eth2spec.test.helpers.keys import privkeys from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing from eth2spec.test.helpers.state import get_balance diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index cd4532457..65d958678 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -56,7 +56,7 @@ def test_single_crosslink_update_from_current_epoch(spec, state): fill_aggregate_attestation(spec, state, attestation) add_attestation_to_state(spec, state, attestation, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY) - assert len(state.current_attestations) == 1 + assert len(state.current_epoch_attestations) == 1 shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) @@ -77,7 +77,7 @@ def test_single_crosslink_update_from_previous_epoch(spec, state): fill_aggregate_attestation(spec, state, attestation) add_attestation_to_state(spec, state, attestation, state.slot + spec.SLOTS_PER_EPOCH) - assert len(state.previous_attestations) == 1 + assert len(state.previous_epoch_attestations) == 1 shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) @@ -130,8 +130,8 @@ def test_double_late_crosslink(spec, state): next_epoch(spec, state) add_attestation_to_state(spec, state, attestation_2, state.slot + 1) - assert len(state.previous_attestations) == 1 - assert len(state.current_attestations) == 0 + assert len(state.previous_epoch_attestations) == 1 + assert len(state.current_epoch_attestations) == 0 crosslink_deltas = spec.get_crosslink_deltas(state) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index a5079b901..967846cb7 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -233,17 +233,17 @@ def test_attestation(spec, state): attestation = get_valid_attestation(spec, state, signed=True) # Add to state via block transition - pre_current_attestations_len = len(state.current_attestations) + pre_current_attestations_len = len(state.current_epoch_attestations) attestation_block = build_empty_block_for_next_slot(spec, state) attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY attestation_block.body.attestations.append(attestation) sign_block(spec, state, attestation_block) spec.state_transition(state, attestation_block) - assert len(state.current_attestations) == pre_current_attestations_len + 1 + assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1 - # Epoch transition should move to previous_attestations - pre_current_attestations_root = spec.hash_tree_root(state.current_attestations) + # Epoch transition should move to previous_epoch_attestations + pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations) epoch_block = build_empty_block_for_next_slot(spec, state) epoch_block.slot += spec.SLOTS_PER_EPOCH @@ -253,8 +253,8 @@ def test_attestation(spec, state): yield 'blocks', [attestation_block, epoch_block], List[spec.BeaconBlock] yield 'post', state - assert len(state.current_attestations) == 0 - assert spec.hash_tree_root(state.previous_attestations) == pre_current_attestations_root + assert len(state.current_epoch_attestations) == 0 + assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root @with_all_phases From 05f1a44a3846b207a089f6ce454060325d4ea77d Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Mon, 10 Jun 2019 21:20:45 +0100 Subject: [PATCH 05/25] Fix tests --- specs/test_formats/operations/README.md | 4 ++-- test_generators/operations/main.py | 4 ++-- test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py | 2 +- .../block_processing/test_process_proposer_slashing.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/test_formats/operations/README.md b/specs/test_formats/operations/README.md index dead3722b..cc7e43f3f 100644 --- a/specs/test_formats/operations/README.md +++ b/specs/test_formats/operations/README.md @@ -23,13 +23,13 @@ Operations: |-------------------------|----------------------|----------------------|--------------------------------------------------------| | `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` | | `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` | -| `parent_block_header` | `Block` | `block` | `process_block_header(state, block)` | +| `block_header` | `Block` | `block` | `process_block_header(state, block)` | | `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` | | `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` | | `transfer` | `Transfer` | `transfer` | `process_transfer(state, transfer)` | | `voluntary_exit` | `VoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` | -Note that `parent_block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here. +Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here. The resulting state should match the expected `post` state, or if the `post` state is left blank, the handler should reject the input operation as invalid. diff --git a/test_generators/operations/main.py b/test_generators/operations/main.py index 70089ebe8..82e05b307 100644 --- a/test_generators/operations/main.py +++ b/test_generators/operations/main.py @@ -42,8 +42,8 @@ if __name__ == "__main__": create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation)), create_suite('attester_slashing', 'minimal', lambda: generate_from_tests(test_process_attester_slashing)), create_suite('attester_slashing', 'mainnet', lambda: generate_from_tests(test_process_attester_slashing)), - create_suite('parent_block_header', 'minimal', lambda: generate_from_tests(test_process_block_header)), - create_suite('parent_block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header)), + create_suite('block_header', 'minimal', lambda: generate_from_tests(test_process_block_header)), + create_suite('block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header)), create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit)), create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit)), create_suite('proposer_slashing', 'minimal', lambda: generate_from_tests(test_process_proposer_slashing)), diff --git a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py index d725f3316..d5b7f7b7f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py +++ b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py @@ -1,6 +1,6 @@ from copy import deepcopy -from eth2spec.test.helpers.parent_block_header import sign_block_header +from eth2spec.test.helpers.block_header import sign_block_header from eth2spec.test.helpers.keys import pubkey_to_privkey diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py index 41039ab06..af34ea709 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_proposer_slashing.py @@ -1,5 +1,5 @@ from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases -from eth2spec.test.helpers.parent_block_header import sign_block_header +from eth2spec.test.helpers.block_header import sign_block_header from eth2spec.test.helpers.keys import privkeys from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing from eth2spec.test.helpers.state import get_balance From 7c0cc7f801259edfad890122ae61e5859548e923 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Jun 2019 14:32:45 -0600 Subject: [PATCH 06/25] fix #1169 bytes type error --- test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 2 ++ test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 2275161c8..1abda292a 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -33,6 +33,7 @@ def test_empty_block_transition(spec, state): assert len(state.eth1_data_votes) == pre_eth1_votes + 1 assert spec.get_block_root_at_slot(state, pre_slot) == block.parent_root + assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.ZERO_HASH @with_all_phases @@ -51,6 +52,7 @@ def test_skipped_slots(spec, state): yield 'post', state assert state.slot == block.slot + assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.ZERO_HASH for slot in range(pre_slot, state.slot): assert spec.get_block_root_at_slot(state, slot) == block.parent_root diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 55ced4ee2..bb98fb084 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -1,3 +1,4 @@ +from types import GeneratorType from typing import List, Iterable, TypeVar, Type, NewType from typing import Union from typing_inspect import get_origin @@ -356,6 +357,8 @@ def parse_bytes(val): return val elif isinstance(val, int): return bytes([val]) + elif isinstance(val, (list, GeneratorType)): + return bytes(val) else: return None From 4a08abfa1d7cb51271b5399dfca68d1c4dc038a4 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Jun 2019 14:47:53 -0600 Subject: [PATCH 07/25] ensure sanity tests run with bls --- test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 2275161c8..f877d81d6 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -13,11 +13,10 @@ from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing from eth2spec.test.helpers.attestations import get_valid_attestation from eth2spec.test.helpers.deposits import prepare_state_and_deposit -from eth2spec.test.context import spec_state_test, never_bls, with_all_phases +from eth2spec.test.context import spec_state_test, with_all_phases @with_all_phases -@never_bls @spec_state_test def test_empty_block_transition(spec, state): pre_slot = state.slot @@ -36,7 +35,6 @@ def test_empty_block_transition(spec, state): @with_all_phases -@never_bls @spec_state_test def test_skipped_slots(spec, state): pre_slot = state.slot From e7bb9bf19bd387842158e8e852bd1df7d2f11e8f Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 01:56:36 +0200 Subject: [PATCH 08/25] SSZ decoding through pyssz, with translation of types/values --- test_libs/fuzzing/decoder.py | 84 ++++++++++++++++++++++++++++++ test_libs/fuzzing/requirements.txt | 3 ++ 2 files changed, 87 insertions(+) create mode 100644 test_libs/fuzzing/decoder.py create mode 100644 test_libs/fuzzing/requirements.txt diff --git a/test_libs/fuzzing/decoder.py b/test_libs/fuzzing/decoder.py new file mode 100644 index 000000000..16d798f6f --- /dev/null +++ b/test_libs/fuzzing/decoder.py @@ -0,0 +1,84 @@ +from eth2spec.utils.ssz import ssz_typing as spec_ssz +import ssz + + +def translate_typ(typ) -> ssz.BaseSedes: + """ + Translates a spec type to a Py-SSZ type description (sedes). + :param typ: The spec type, a class. + :return: The Py-SSZ equivalent. + """ + if spec_ssz.is_container_type(typ): + return ssz.Container( + [(field_name, translate_typ(field_typ)) for (field_name, field_typ) in typ.get_fields()]) + elif spec_ssz.is_bytesn_type(typ): + return ssz.ByteVector(typ.length) + elif spec_ssz.is_bytes_type(typ): + return ssz.ByteList() + elif spec_ssz.is_vector_type(typ): + return ssz.Vector(translate_typ(spec_ssz.read_vector_elem_type(typ)), typ.length) + elif spec_ssz.is_list_type(typ): + return ssz.List(translate_typ(spec_ssz.read_list_elem_type(typ))) + elif spec_ssz.is_bool_type(typ): + return ssz.boolean + elif spec_ssz.is_uint_type(typ): + size = spec_ssz.uint_byte_size(typ) + if size == 1: + return ssz.uint8 + elif size == 2: + return ssz.uint16 + elif size == 4: + return ssz.uint32 + elif size == 8: + return ssz.uint64 + elif size == 16: + return ssz.uint128 + elif size == 32: + return ssz.uint256 + else: + raise TypeError("invalid uint size") + else: + raise Exception("Type not supported: {}".format(typ)) + + +def translate_value(value, typ): + """ + Translate a value output from Py-SSZ deserialization into the given spec type. + :param value: The PySSZ value + :param typ: The type from the spec to translate into + :return: the translated value + """ + if spec_ssz.is_uint_type(typ): + size = spec_ssz.uint_byte_size(typ) + if size == 1: + return spec_ssz.uint8(value) + elif size == 2: + return spec_ssz.uint16(value) + elif size == 4: + return spec_ssz.uint32(value) + elif size == 8: + # uint64 is default (TODO this is changing soon) + return value + elif size == 16: + return spec_ssz.uint128(value) + elif size == 32: + return spec_ssz.uint256(value) + else: + raise TypeError("invalid uint size") + elif spec_ssz.is_list_type(typ): + elem_typ = spec_ssz.read_elem_type(typ) + return [translate_value(elem, elem_typ) for elem in value] + elif spec_ssz.is_bool_type(typ): + return False + elif spec_ssz.is_vector_type(typ): + elem_typ = spec_ssz.read_elem_type(typ) + return typ(translate_value(elem, elem_typ) for elem in value) + elif spec_ssz.is_bytesn_type(typ): + return typ(value) + elif spec_ssz.is_bytes_type(typ): + return value + elif spec_ssz.is_container_type(typ): + return typ(**{f_name: translate_value(f_val, f_typ) for (f_name, f_val, f_typ) + in zip(typ.get_field_names(), value.values(), typ.get_field_types())}) + else: + raise Exception("Type not supported: {}".format(typ)) diff --git a/test_libs/fuzzing/requirements.txt b/test_libs/fuzzing/requirements.txt new file mode 100644 index 000000000..98dcd9564 --- /dev/null +++ b/test_libs/fuzzing/requirements.txt @@ -0,0 +1,3 @@ +../../test_libs/pyspec +../../test_libs/config_helpers +ssz==0.1.0a8 From c391017a0557bcb6f3060619fac48d7798b036eb Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Jun 2019 17:57:29 -0600 Subject: [PATCH 09/25] address #1146 by inserting state root and re-signing blocks in tests --- .../pyspec/eth2spec/test/helpers/state.py | 13 ++++ .../test_process_crosslinks.py | 8 ++- .../test_process_registry_updates.py | 5 +- .../eth2spec/test/sanity/test_blocks.py | 62 +++++++++++-------- .../pyspec/eth2spec/test/test_finality.py | 4 +- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/helpers/state.py b/test_libs/pyspec/eth2spec/test/helpers/state.py index 63aa27d70..8641d4c0d 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/state.py +++ b/test_libs/pyspec/eth2spec/test/helpers/state.py @@ -1,3 +1,6 @@ +from eth2spec.test.helpers.block import sign_block + + def get_balance(state, index): return state.balances[index] @@ -23,3 +26,13 @@ def get_state_root(spec, state, slot) -> bytes: """ assert slot < state.slot <= slot + spec.SLOTS_PER_HISTORICAL_ROOT return state.latest_state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT] + + +def state_transition_and_sign_block(spec, state, block): + """ + State transition via the provided ``block`` + then package the block with the state root and signature. + """ + spec.state_transition(state, block) + block.state_root = state.hash_tree_root() + sign_block(spec, state, block) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index 65d958678..d51191efb 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -3,7 +3,8 @@ from copy import deepcopy from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.helpers.state import ( next_epoch, - next_slot + next_slot, + state_transition_and_sign_block, ) from eth2spec.test.helpers.block import apply_empty_block, sign_block from eth2spec.test.helpers.attestations import ( @@ -27,11 +28,14 @@ def run_process_crosslinks(spec, state, valid=True): block = build_empty_block_for_next_slot(spec, state) block.slot = slot sign_block(spec, state, block) - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) # cache state before epoch transition spec.process_slot(state) + # process components of epoch transition before processing crosslinks + spec.process_justification_and_finalization(state) + yield 'pre', state spec.process_crosslinks(state) yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index e6679f844..4f6d700b7 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -1,6 +1,5 @@ -from eth2spec.phase0.spec import state_transition from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block -from eth2spec.test.helpers.state import next_epoch +from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block from eth2spec.test.context import spec_state_test, with_all_phases @@ -16,7 +15,7 @@ def run_process_registry_updates(spec, state, valid=True): block = build_empty_block_for_next_slot(spec, state) block.slot = slot sign_block(spec, state, block) - state_transition(state, block) + state_transition_and_sign_block(spec, state, block) # cache state before epoch transition spec.process_slot(state) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 347c67a19..f333531e7 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -4,7 +4,7 @@ from typing import List from eth2spec.utils.ssz.ssz_impl import signing_root from eth2spec.utils.bls import bls_sign -from eth2spec.test.helpers.state import get_balance +from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block # from eth2spec.test.helpers.transfers import get_valid_transfer from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block from eth2spec.test.helpers.keys import privkeys, pubkeys @@ -16,6 +16,7 @@ from eth2spec.test.helpers.deposits import prepare_state_and_deposit from eth2spec.test.context import spec_state_test, with_all_phases + @with_all_phases @spec_state_test def test_empty_block_transition(spec, state): @@ -25,9 +26,10 @@ def test_empty_block_transition(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state, signed=True) - yield 'blocks', [block], List[spec.BeaconBlock] - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state assert len(state.eth1_data_votes) == pre_eth1_votes + 1 @@ -44,9 +46,10 @@ def test_skipped_slots(spec, state): block = build_empty_block_for_next_slot(spec, state) block.slot += 3 sign_block(spec, state, block) - yield 'blocks', [block], List[spec.BeaconBlock] - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state assert state.slot == block.slot @@ -64,9 +67,10 @@ def test_empty_epoch_transition(spec, state): block = build_empty_block_for_next_slot(spec, state) block.slot += spec.SLOTS_PER_EPOCH sign_block(spec, state, block) - yield 'blocks', [block], List[spec.BeaconBlock] - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state assert state.slot == block.slot @@ -84,9 +88,10 @@ def test_empty_epoch_transition(spec, state): # block = build_empty_block_for_next_slot(spec, state) # block.slot += spec.SLOTS_PER_EPOCH * 5 # sign_block(spec, state, block, proposer_index=0) -# yield 'blocks', [block], List[spec.BeaconBlock] -# spec.state_transition(state, block) +# state_transition_and_sign_block(spec, state, block) + +# yield 'blocks', [block], List[spec.BeaconBlock] # yield 'post', state # assert state.slot == block.slot @@ -113,9 +118,10 @@ def test_proposer_slashing(spec, state): block = build_empty_block_for_next_slot(spec, state) block.body.proposer_slashings.append(proposer_slashing) sign_block(spec, state, block) - yield 'blocks', [block], List[spec.BeaconBlock] - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state # check if slashed @@ -147,9 +153,10 @@ def test_attester_slashing(spec, state): block = build_empty_block_for_next_slot(spec, state) block.body.attester_slashings.append(attester_slashing) sign_block(spec, state, block) - yield 'blocks', [block], List[spec.BeaconBlock] - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state slashed_validator = state.validator_registry[validator_index] @@ -185,9 +192,9 @@ def test_deposit_in_block(spec, state): block.body.deposits.append(deposit) sign_block(spec, state, block) - yield 'blocks', [block], List[spec.BeaconBlock] + state_transition_and_sign_block(spec, state, block) - spec.state_transition(state, block) + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state assert len(state.validator_registry) == initial_registry_len + 1 @@ -213,9 +220,9 @@ def test_deposit_top_up(spec, state): block.body.deposits.append(deposit) sign_block(spec, state, block) - yield 'blocks', [block], List[spec.BeaconBlock] + state_transition_and_sign_block(spec, state, block) - spec.state_transition(state, block) + yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state assert len(state.validator_registry) == initial_registry_len @@ -238,7 +245,7 @@ def test_attestation(spec, state): attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY attestation_block.body.attestations.append(attestation) sign_block(spec, state, attestation_block) - spec.state_transition(state, attestation_block) + state_transition_and_sign_block(spec, state, attestation_block) assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1 @@ -248,7 +255,8 @@ def test_attestation(spec, state): epoch_block = build_empty_block_for_next_slot(spec, state) epoch_block.slot += spec.SLOTS_PER_EPOCH sign_block(spec, state, epoch_block) - spec.state_transition(state, epoch_block) + state_transition_and_sign_block(spec, state, epoch_block) + yield 'blocks', [attestation_block, epoch_block], List[spec.BeaconBlock] yield 'post', state @@ -287,7 +295,7 @@ def test_voluntary_exit(spec, state): initiate_exit_block = build_empty_block_for_next_slot(spec, state) initiate_exit_block.body.voluntary_exits.append(voluntary_exit) sign_block(spec, state, initiate_exit_block) - spec.state_transition(state, initiate_exit_block) + state_transition_and_sign_block(spec, state, initiate_exit_block) assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH @@ -295,7 +303,7 @@ def test_voluntary_exit(spec, state): exit_block = build_empty_block_for_next_slot(spec, state) exit_block.slot += spec.SLOTS_PER_EPOCH sign_block(spec, state, exit_block) - spec.state_transition(state, exit_block) + state_transition_and_sign_block(spec, state, exit_block) yield 'blocks', [initiate_exit_block, exit_block], List[spec.BeaconBlock] yield 'post', state @@ -326,9 +334,9 @@ def test_voluntary_exit(spec, state): # block.body.transfers.append(transfer) # sign_block(spec, state, block) - # yield 'blocks', [block], List[spec.BeaconBlock] + # state_transition_and_sign_block(spec, state, block) - # spec.state_transition(state, block) + # yield 'blocks', [block], List[spec.BeaconBlock] # yield 'post', state # sender_balance = get_balance(state, sender_index) @@ -354,7 +362,7 @@ def test_balance_driven_status_transitions(spec, state): block = build_empty_block_for_next_slot(spec, state) block.slot += spec.SLOTS_PER_EPOCH sign_block(spec, state, block) - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state @@ -371,7 +379,7 @@ def test_historical_batch(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state, signed=True) - spec.state_transition(state, block) + state_transition_and_sign_block(spec, state, block) yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state @@ -392,7 +400,7 @@ def test_historical_batch(spec, state): # blocks = [] # for _ in range(spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1): # block = build_empty_block_for_next_slot(spec, state) -# spec.state_transition(state, block) +# state_transition_and_sign_block(spec, state, block) # expected_votes += 1 # assert len(state.eth1_data_votes) == expected_votes # blocks.append(block) @@ -400,7 +408,7 @@ def test_historical_batch(spec, state): # block = build_empty_block_for_next_slot(spec, state) # blocks.append(block) -# spec.state_transition(state, block) +# state_transition_and_sign_block(spec, state, block) # yield 'blocks', [block], List[spec.BeaconBlock] # yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/test_finality.py b/test_libs/pyspec/eth2spec/test/test_finality.py index 801e8b4fd..5e81f52c8 100644 --- a/test_libs/pyspec/eth2spec/test/test_finality.py +++ b/test_libs/pyspec/eth2spec/test/test_finality.py @@ -2,7 +2,7 @@ from copy import deepcopy from typing import List from eth2spec.test.context import spec_state_test, never_bls, with_all_phases -from eth2spec.test.helpers.state import next_epoch +from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block from eth2spec.test.helpers.block import build_empty_block_for_next_slot, apply_empty_block from eth2spec.test.helpers.attestations import get_valid_attestation @@ -54,7 +54,7 @@ def next_epoch_with_attestations(spec, prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest) block.body.attestations.append(prev_attestation) - spec.state_transition(post_state, block) + state_transition_and_sign_block(spec, post_state, block) blocks.append(block) return state, blocks, post_state From f834f727fa210c442231f6aea6542a08e0e1e669 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Jun 2019 18:03:20 -0600 Subject: [PATCH 10/25] lint --- test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index f333531e7..e19fbc97c 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -16,7 +16,6 @@ from eth2spec.test.helpers.deposits import prepare_state_and_deposit from eth2spec.test.context import spec_state_test, with_all_phases - @with_all_phases @spec_state_test def test_empty_block_transition(spec, state): @@ -257,7 +256,6 @@ def test_attestation(spec, state): sign_block(spec, state, epoch_block) state_transition_and_sign_block(spec, state, epoch_block) - yield 'blocks', [attestation_block, epoch_block], List[spec.BeaconBlock] yield 'post', state From aed5db033a8c52f0263da7f0671c0c172d62d6e9 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 14 Jun 2019 10:15:54 -0600 Subject: [PATCH 11/25] enforce byte length for g2 values in test generators --- test_generators/bls/main.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test_generators/bls/main.py b/test_generators/bls/main.py index ef80635de..8a6a7dafe 100644 --- a/test_generators/bls/main.py +++ b/test_generators/bls/main.py @@ -12,8 +12,15 @@ from gen_base import gen_runner, gen_suite, gen_typing from py_ecc import bls -def int_to_hex(n: int) -> str: - return '0x' + int_to_big_endian(n).hex() +F2Q_COEFF_LEN = 48 +G2_COMPRESSED_Z_LEN = 48 + + +def int_to_hex(n: int, byte_length: int=None) -> str: + byte_value = int_to_big_endian(n) + if byte_length: + byte_value = byte_value.rjust(byte_length, b'\x00') + return '0x' + byte_value.hex() def hex_to_int(x: str) -> int: @@ -58,8 +65,8 @@ def hash_message(msg: bytes, """ return [ [ - int_to_hex(fq2.coeffs[0]), - int_to_hex(fq2.coeffs[1]), + int_to_hex(fq2.coeffs[0], F2Q_COEFF_LEN), + int_to_hex(fq2.coeffs[1], F2Q_COEFF_LEN), ] for fq2 in bls.utils.hash_to_G2(msg, domain) ] @@ -75,8 +82,7 @@ def hash_message_compressed(msg: bytes, domain: int) -> Tuple[str, str]: - Message hash as a compressed G2 point """ z1, z2 = bls.utils.compress_G2(bls.utils.hash_to_G2(msg, domain)) - return [int_to_hex(z1), int_to_hex(z2)] - + return [int_to_hex(z1, G2_COMPRESSED_Z_LEN), int_to_hex(z2, G2_COMPRESSED_Z_LEN)] @to_tuple From 7b0ffc1ace8eefb61d459cddff94969a9601df52 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 19:09:49 +0200 Subject: [PATCH 12/25] move decoder for fuzzing, minor fixes, update dependency to support SOS style offsets --- test_libs/fuzzing/requirements.txt | 3 --- test_libs/pyspec/eth2spec/fuzzing/__init__.py | 0 test_libs/{ => pyspec/eth2spec}/fuzzing/decoder.py | 8 ++++---- test_libs/pyspec/requirements.txt | 1 + test_libs/pyspec/setup.py | 3 ++- 5 files changed, 7 insertions(+), 8 deletions(-) delete mode 100644 test_libs/fuzzing/requirements.txt create mode 100644 test_libs/pyspec/eth2spec/fuzzing/__init__.py rename test_libs/{ => pyspec/eth2spec}/fuzzing/decoder.py (89%) diff --git a/test_libs/fuzzing/requirements.txt b/test_libs/fuzzing/requirements.txt deleted file mode 100644 index 98dcd9564..000000000 --- a/test_libs/fuzzing/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -../../test_libs/pyspec -../../test_libs/config_helpers -ssz==0.1.0a8 diff --git a/test_libs/pyspec/eth2spec/fuzzing/__init__.py b/test_libs/pyspec/eth2spec/fuzzing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test_libs/fuzzing/decoder.py b/test_libs/pyspec/eth2spec/fuzzing/decoder.py similarity index 89% rename from test_libs/fuzzing/decoder.py rename to test_libs/pyspec/eth2spec/fuzzing/decoder.py index 16d798f6f..bb8aceb61 100644 --- a/test_libs/fuzzing/decoder.py +++ b/test_libs/pyspec/eth2spec/fuzzing/decoder.py @@ -10,7 +10,7 @@ def translate_typ(typ) -> ssz.BaseSedes: """ if spec_ssz.is_container_type(typ): return ssz.Container( - [(field_name, translate_typ(field_typ)) for (field_name, field_typ) in typ.get_fields()]) + [translate_typ(field_typ) for (field_name, field_typ) in typ.get_fields()]) elif spec_ssz.is_bytesn_type(typ): return ssz.ByteVector(typ.length) elif spec_ssz.is_bytes_type(typ): @@ -38,7 +38,7 @@ def translate_typ(typ) -> ssz.BaseSedes: else: raise TypeError("invalid uint size") else: - raise Exception("Type not supported: {}".format(typ)) + raise TypeError("Type not supported: {}".format(typ)) def translate_value(value, typ): @@ -79,6 +79,6 @@ def translate_value(value, typ): return value elif spec_ssz.is_container_type(typ): return typ(**{f_name: translate_value(f_val, f_typ) for (f_name, f_val, f_typ) - in zip(typ.get_field_names(), value.values(), typ.get_field_types())}) + in zip(typ.get_field_names(), value, typ.get_field_types())}) else: - raise Exception("Type not supported: {}".format(typ)) + raise TypeError("Type not supported: {}".format(typ)) diff --git a/test_libs/pyspec/requirements.txt b/test_libs/pyspec/requirements.txt index 3b38930bd..eed0d5a7d 100644 --- a/test_libs/pyspec/requirements.txt +++ b/test_libs/pyspec/requirements.txt @@ -3,3 +3,4 @@ eth-typing>=2.1.0,<3.0.0 pycryptodome==3.7.3 py_ecc>=1.6.0 typing_inspect==0.4.0 +ssz==0.1.0a9 diff --git a/test_libs/pyspec/setup.py b/test_libs/pyspec/setup.py index e99b911ee..49f3c84a1 100644 --- a/test_libs/pyspec/setup.py +++ b/test_libs/pyspec/setup.py @@ -9,6 +9,7 @@ setup( "eth-typing>=2.1.0,<3.0.0", "pycryptodome==3.7.3", "py_ecc>=1.6.0", - "typing_inspect==0.4.0" + "typing_inspect==0.4.0", + "ssz==0.1.0a9" ] ) From 01be8b7e656de4bfce86136dac79774eefeea3e5 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 19:16:15 +0200 Subject: [PATCH 13/25] minor fix --- test_libs/pyspec/eth2spec/fuzzing/decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/fuzzing/decoder.py b/test_libs/pyspec/eth2spec/fuzzing/decoder.py index bb8aceb61..5722ed297 100644 --- a/test_libs/pyspec/eth2spec/fuzzing/decoder.py +++ b/test_libs/pyspec/eth2spec/fuzzing/decoder.py @@ -69,7 +69,7 @@ def translate_value(value, typ): elem_typ = spec_ssz.read_elem_type(typ) return [translate_value(elem, elem_typ) for elem in value] elif spec_ssz.is_bool_type(typ): - return False + return value elif spec_ssz.is_vector_type(typ): elem_typ = spec_ssz.read_elem_type(typ) return typ(translate_value(elem, elem_typ) for elem in value) From 895ab67815866c2a3f78022fc8dc6ad575f4b1fc Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 20:41:08 +0200 Subject: [PATCH 14/25] fix decoder, also fix bug in pyssz, see PR 74 --- test_libs/pyspec/eth2spec/fuzzing/decoder.py | 2 +- .../pyspec/eth2spec/fuzzing/test_decoder.py | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test_libs/pyspec/eth2spec/fuzzing/test_decoder.py diff --git a/test_libs/pyspec/eth2spec/fuzzing/decoder.py b/test_libs/pyspec/eth2spec/fuzzing/decoder.py index 5722ed297..a5d3dfd97 100644 --- a/test_libs/pyspec/eth2spec/fuzzing/decoder.py +++ b/test_libs/pyspec/eth2spec/fuzzing/decoder.py @@ -72,7 +72,7 @@ def translate_value(value, typ): return value elif spec_ssz.is_vector_type(typ): elem_typ = spec_ssz.read_elem_type(typ) - return typ(translate_value(elem, elem_typ) for elem in value) + return typ(*(translate_value(elem, elem_typ) for elem in value)) elif spec_ssz.is_bytesn_type(typ): return typ(value) elif spec_ssz.is_bytes_type(typ): diff --git a/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py b/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py new file mode 100644 index 000000000..3747b3535 --- /dev/null +++ b/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py @@ -0,0 +1,39 @@ +from eth2spec.fuzzing.decoder import translate_typ, translate_value +from eth2spec.phase0 import spec +from preset_loader import loader +from eth2spec.utils.ssz import ssz_impl as spec_ssz_impl +from random import Random +from eth2spec.debug import random_value + + +def test_decoder(): + configs_path = "../../../../configs/" + config_name = "minimal" + presets = loader.load_presets(configs_path, config_name) + spec.apply_constants_preset(presets) + + rng = Random(123) + + # check these types only, Block covers a lot of operation types already. + for typ in [spec.BeaconBlock, spec.BeaconState, spec.IndexedAttestation, spec.AttestationDataAndCustodyBit]: + # create a random pyspec value + original = random_value.get_random_ssz_object(rng, typ, 100, 10, + mode=random_value.RandomizationMode.mode_random, + chaos=True) + # serialize it, using pyspec + pyspec_data = spec_ssz_impl.serialize(original) + # get the py-ssz type for it + block_sedes = translate_typ(typ) + # try decoding using the py-ssz type + raw_value = block_sedes.deserialize(pyspec_data) + + # serialize it using py-ssz + pyssz_data = block_sedes.serialize(raw_value) + # now check if the serialized form is equal. If so, we confirmed decoding and encoding to work. + assert pyspec_data == pyssz_data + + # now translate the py-ssz value in a pyspec-value + block = translate_value(raw_value, typ) + + # and see if the hash-tree-root of the original matches the hash-tree-root of the decoded & translated value. + assert spec_ssz_impl.hash_tree_root(original) == spec_ssz_impl.hash_tree_root(block) From d4bf55e5a10f505f6e767e2864d9632f805c5763 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 21:24:24 +0200 Subject: [PATCH 15/25] update pyssz to include deserialization bugfix --- test_libs/pyspec/requirements.txt | 2 +- test_libs/pyspec/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/requirements.txt b/test_libs/pyspec/requirements.txt index eed0d5a7d..2de2aa84b 100644 --- a/test_libs/pyspec/requirements.txt +++ b/test_libs/pyspec/requirements.txt @@ -3,4 +3,4 @@ eth-typing>=2.1.0,<3.0.0 pycryptodome==3.7.3 py_ecc>=1.6.0 typing_inspect==0.4.0 -ssz==0.1.0a9 +ssz==0.1.0a10 diff --git a/test_libs/pyspec/setup.py b/test_libs/pyspec/setup.py index 49f3c84a1..3856640ab 100644 --- a/test_libs/pyspec/setup.py +++ b/test_libs/pyspec/setup.py @@ -10,6 +10,6 @@ setup( "pycryptodome==3.7.3", "py_ecc>=1.6.0", "typing_inspect==0.4.0", - "ssz==0.1.0a9" + "ssz==0.1.0a10" ] ) From 367586d888ae5bc901a81588227926971b40585f Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 21:31:33 +0200 Subject: [PATCH 16/25] remove need for presets loading, just test mainnet, not too many/large objects anyway --- test_libs/pyspec/eth2spec/fuzzing/test_decoder.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py b/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py index 3747b3535..26ee6e913 100644 --- a/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py +++ b/test_libs/pyspec/eth2spec/fuzzing/test_decoder.py @@ -1,17 +1,11 @@ from eth2spec.fuzzing.decoder import translate_typ, translate_value from eth2spec.phase0 import spec -from preset_loader import loader from eth2spec.utils.ssz import ssz_impl as spec_ssz_impl from random import Random from eth2spec.debug import random_value def test_decoder(): - configs_path = "../../../../configs/" - config_name = "minimal" - presets = loader.load_presets(configs_path, config_name) - spec.apply_constants_preset(presets) - rng = Random(123) # check these types only, Block covers a lot of operation types already. From 1c51982c6b5de8fd9dfb851cb85086fa83205d52 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 14 Jun 2019 23:12:04 +0200 Subject: [PATCH 17/25] generate coverage reports in make test, open as html site --- .gitignore | 7 +++++++ Makefile | 14 ++++++++++---- test_libs/pyspec/requirements-testing.txt | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c6b39955f..16d39a434 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,10 @@ eth2.0-spec-tests/ # Dynamically built from Markdown spec test_libs/pyspec/eth2spec/phase0/spec.py test_libs/pyspec/eth2spec/phase1/spec.py + +# coverage reports +.htmlcov +.coverage + +# local CI testing output +test_libs/pyspec/test-reports diff --git a/Makefile b/Makefile index f79b89dad..9e658f35d 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,10 @@ PY_SPEC_PHASE_1_DEPS = $(SPEC_DIR)/core/1_*.md PY_SPEC_ALL_TARGETS = $(PY_SPEC_PHASE_0_TARGETS) $(PY_SPEC_PHASE_1_TARGETS) +COV_INDEX_FILE=$(PY_SPEC_DIR)/.htmlcov/index.html -.PHONY: clean all test citest lint gen_yaml_tests pyspec phase0 phase1 install_test install_deposit_contract_test test_deposit_contract compile_deposit_contract +.PHONY: clean all test citest lint gen_yaml_tests pyspec phase0 phase1 install_test open_cov \ + install_deposit_contract_test test_deposit_contract compile_deposit_contract all: $(PY_SPEC_ALL_TARGETS) $(YAML_TEST_DIR) $(YAML_TEST_TARGETS) @@ -41,11 +43,15 @@ install_test: cd $(PY_SPEC_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install -r requirements-testing.txt; test: $(PY_SPEC_ALL_TARGETS) - cd $(PY_SPEC_DIR); . venv/bin/activate; python -m pytest eth2spec + cd $(PY_SPEC_DIR); . venv/bin/activate; export PYTHONPATH="./"; \ + python -m pytest --cov=eth2spec.phase0.spec --cov=eth2spec.phase1.spec --cov-report="html:.htmlcov" --cov-branch eth2spec 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_phase0.xml eth2spec + cd $(PY_SPEC_DIR); mkdir -p test-reports/eth2spec; . venv/bin/activate; \ + python -m pytest --junitxml=test-reports/eth2spec/test_results.xml eth2spec + +open_cov: + ((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) & lint: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); . venv/bin/activate; \ diff --git a/test_libs/pyspec/requirements-testing.txt b/test_libs/pyspec/requirements-testing.txt index 331d0fa28..edd141650 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 +pytest-cov From 20aa539f4dc3903a7f73fac2a4d26e257b34ee26 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 15 Jun 2019 01:13:29 +0200 Subject: [PATCH 18/25] update clean command --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9e658f35d..1b7155625 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ PY_SPEC_PHASE_1_DEPS = $(SPEC_DIR)/core/1_*.md PY_SPEC_ALL_TARGETS = $(PY_SPEC_PHASE_0_TARGETS) $(PY_SPEC_PHASE_1_TARGETS) -COV_INDEX_FILE=$(PY_SPEC_DIR)/.htmlcov/index.html +COV_HTML_OUT=.htmlcov +COV_INDEX_FILE=$(PY_SPEC_DIR)/$(COV_HTML_OUT)/index.html .PHONY: clean all test citest lint gen_yaml_tests pyspec phase0 phase1 install_test open_cov \ install_deposit_contract_test test_deposit_contract compile_deposit_contract @@ -34,6 +35,9 @@ clean: rm -rf $(PY_SPEC_DIR)/venv $(PY_SPEC_DIR)/.pytest_cache rm -rf $(PY_SPEC_ALL_TARGETS) rm -rf $(DEPOSIT_CONTRACT_DIR)/venv $(DEPOSIT_CONTRACT_DIR)/.pytest_cache + rm -rf $(PY_SPEC_DIR)/$(COV_HTML_OUT) + rm -rf $(PY_SPEC_DIR)/.coverage + rm -rf $(PY_SPEC_DIR)/test-reports # "make gen_yaml_tests" to run generators gen_yaml_tests: $(PY_SPEC_ALL_TARGETS) $(YAML_TEST_TARGETS) @@ -44,7 +48,7 @@ install_test: test: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); . venv/bin/activate; export PYTHONPATH="./"; \ - python -m pytest --cov=eth2spec.phase0.spec --cov=eth2spec.phase1.spec --cov-report="html:.htmlcov" --cov-branch eth2spec + python -m pytest --cov=eth2spec.phase0.spec --cov=eth2spec.phase1.spec --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec -k transfer citest: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); mkdir -p test-reports/eth2spec; . venv/bin/activate; \ From ed748a7d769e3d81697a2df92f1638cccf9c5057 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 15 Jun 2019 15:09:50 +0100 Subject: [PATCH 19/25] Address Danny's comments --- scripts/build_spec.py | 2 +- specs/core/0_beacon-chain.md | 14 +++++++------- specs/core/0_fork-choice.md | 4 ++-- test_libs/pyspec/eth2spec/test/helpers/block.py | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index e25147a7f..eae9b60d5 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -62,7 +62,6 @@ from eth2spec.utils.bls import ( from eth2spec.utils.hash_function import hash ''' -BYTE_TYPES = [4, 32, 48, 96] NEW_TYPES = { 'Slot': 'int', 'Epoch': 'int', @@ -70,6 +69,7 @@ NEW_TYPES = { 'ValidatorIndex': 'int', 'Gwei': 'int', } +BYTE_TYPES = [4, 32, 48, 96] SUNDRY_FUNCTIONS = ''' def get_ssz_type_by_name(name: str) -> Container: return globals()[name] diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b4049bb30..367a1cceb 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -493,7 +493,7 @@ class BeaconState(Container): slot: Slot fork: Fork # History - parent_block_header: BeaconBlockHeader + latest_block_header: BeaconBlockHeader block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT] historical_roots: List[Hash] @@ -1152,7 +1152,7 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis state = BeaconState( genesis_time=genesis_time, eth1_data=genesis_eth1_data, - parent_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) # Process genesis deposits @@ -1212,11 +1212,11 @@ def process_slot(state: BeaconState) -> None: state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root # Cache latest block header state root - if state.parent_block_header.state_root == ZERO_HASH: - state.parent_block_header.state_root = previous_state_root + if state.latest_block_header.state_root == ZERO_HASH: + state.latest_block_header.state_root = previous_state_root # Cache block root - previous_block_root = signing_root(state.parent_block_header) + previous_block_root = signing_root(state.latest_block_header) state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root ``` @@ -1556,9 +1556,9 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None: # Verify that the slots match assert block.slot == state.slot # Verify that the parent matches - assert block.parent_root == signing_root(state.parent_block_header) + assert block.parent_root == signing_root(state.latest_block_header) # Save current block as the new latest block - state.parent_block_header = BeaconBlockHeader( + state.latest_block_header = BeaconBlockHeader( slot=block.slot, parent_root=block.parent_root, body_root=hash_tree_root(block.body), diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index 739c06d59..8103bbeb2 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -68,8 +68,8 @@ def get_ancestor(store: Store, block: BeaconBlock, slot: Slot) -> BeaconBlock: return get_ancestor(store, store.get_parent(block), slot) ``` -* Let `get_attestation(store: Store, index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `index`. If several such attestations exist, use the one the validator `v` observed first. -* Let `get_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_attestation(store, index)`. +* Let `get_latest_attestation(store: Store, index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `index`. If several such attestations exist, use the one the validator `v` observed first. +* Let `get_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, index)`. * Let `get_children(store: Store, block: BeaconBlock) -> List[BeaconBlock]` return the child blocks of the given `block`. * Let `justified_head_state` be the resulting `BeaconState` object from processing the chain up to the `justified_head`. * The `head` is `lmd_ghost(store, justified_head_state, justified_head)` where the function `lmd_ghost` is defined below. Note that the implementation below is suboptimal; there are implementations that compute the head in time logarithmic in slot count. diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index 03f8d5b7e..16249fe93 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -58,7 +58,7 @@ def build_empty_block(spec, state, slot=None, signed=False): empty_block = spec.BeaconBlock() empty_block.slot = slot empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index - previous_block_header = deepcopy(state.parent_block_header) + previous_block_header = deepcopy(state.latest_block_header) if previous_block_header.state_root == spec.ZERO_HASH: previous_block_header.state_root = state.hash_tree_root() empty_block.parent_root = signing_root(previous_block_header) From 7cd7659a4b68ad515231ba635a800ae69e5f6798 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 15 Jun 2019 15:51:17 +0100 Subject: [PATCH 20/25] Add comments to non-obvious container fields --- specs/core/0_beacon-chain.md | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 367a1cceb..cc4500d3f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -283,7 +283,7 @@ The following types are [SimpleSerialize (SSZ)](../simple-serialize.md) containe class Fork(Container): previous_version: Bytes4 current_version: Bytes4 - epoch: Epoch + epoch: Epoch # Epoch of latest fork ``` #### `Validator` @@ -291,14 +291,14 @@ class Fork(Container): ```python class Validator(Container): pubkey: BLSPubkey - withdrawal_credentials: Hash - effective_balance: Gwei + withdrawal_credentials: Hash # Commitment to pubkey for withdrawals and transfers + effective_balance: Gwei # Balance at stake slashed: bool # Status epochs - activation_eligibility_epoch: Epoch + activation_eligibility_epoch: Epoch # When criteria for activation were met activation_epoch: Epoch exit_epoch: Epoch - withdrawable_epoch: Epoch + withdrawable_epoch: Epoch # When validator can withdraw or transfer funds ``` #### `Crosslink` @@ -333,7 +333,7 @@ class AttestationData(Container): ```python class AttestationDataAndCustodyBit(Container): data: AttestationData - custody_bit: bool + custody_bit: bool # Challengeable bit for the custody of crosslink data ``` #### `IndexedAttestation` @@ -350,7 +350,7 @@ class IndexedAttestation(Container): ```python class PendingAttestation(Container): - aggregation_bitfield: bytes + aggregation_bitfield: bytes # Bit set for every attesting participant within a committee data: AttestationData inclusion_delay: Slot proposer_index: ValidatorIndex @@ -427,7 +427,7 @@ class Attestation(Container): ```python class Deposit(Container): - proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Merkle path to deposit root data: DepositData ``` @@ -435,7 +435,7 @@ class Deposit(Container): ```python class VoluntaryExit(Container): - epoch: Epoch + epoch: Epoch # Earliest epoch when voluntary exit can be processed validator_index: ValidatorIndex signature: BLSSignature ``` @@ -448,9 +448,9 @@ class Transfer(Container): recipient: ValidatorIndex amount: Gwei fee: Gwei - slot: Slot - pubkey: BLSPubkey - signature: BLSSignature + slot: Slot # Slot at which transfer must be processed + pubkey: BLSPubkey # Withdrawal pubkey + signature: BLSSignature # Signature checked against withdrawal pubkey ``` ### Beacon blocks @@ -460,8 +460,8 @@ class Transfer(Container): ```python class BeaconBlockBody(Container): randao_reveal: BLSSignature - eth1_data: Eth1Data - graffiti: Bytes32 + eth1_data: Eth1Data # Eth1 data vote + graffiti: Bytes32 # Arbitrary data # Operations proposer_slashings: List[ProposerSlashing] attester_slashings: List[AttesterSlashing] @@ -507,21 +507,21 @@ class BeaconState(Container): # Shuffling start_shard: Shard randao_mixes: Vector[Hash, RANDAO_MIXES_LENGTH] - active_index_roots: Vector[Hash, ACTIVE_INDEX_ROOTS_LENGTH] + active_index_roots: Vector[Hash, ACTIVE_INDEX_ROOTS_LENGTH] # Digests of the active registry, for light clients # Slashings - slashed_balances: Vector[Gwei, SLASHED_EXIT_LENGTH] + slashed_balances: Vector[Gwei, SLASHED_EXIT_LENGTH] # Sums of the effective balances of slashed validators # Attestations previous_epoch_attestations: List[PendingAttestation] current_epoch_attestations: List[PendingAttestation] # Crosslinks - previous_crosslinks: Vector[Crosslink, SHARD_COUNT] + previous_crosslinks: Vector[Crosslink, SHARD_COUNT] # Previous epoch snapshot current_crosslinks: Vector[Crosslink, SHARD_COUNT] # Justification - previous_justified_epoch: Epoch - previous_justified_root: Hash + previous_justified_epoch: Epoch # Previous epoch snapshot + previous_justified_root: Hash # Previous epoch snapshot current_justified_epoch: Epoch current_justified_root: Hash - justification_bitfield: uint64 + justification_bitfield: uint64 # Bit set for every recent justified epoch # Finality finalized_epoch: Epoch finalized_root: Hash From 75b469281e870523a4145e8c7bdcf2da9a166aac Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 15 Jun 2019 18:05:01 +0200 Subject: [PATCH 21/25] fix linting issue --- 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 cc4500d3f..968098895 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -298,7 +298,7 @@ class Validator(Container): activation_eligibility_epoch: Epoch # When criteria for activation were met activation_epoch: Epoch exit_epoch: Epoch - withdrawable_epoch: Epoch # When validator can withdraw or transfer funds + withdrawable_epoch: Epoch # When validator can withdraw or transfer funds ``` #### `Crosslink` From 2f9c554bf7370319bfc0d61feaaf2a34338583b9 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sun, 16 Jun 2019 17:38:48 -0600 Subject: [PATCH 22/25] minor fix to makefile, add codecov instructiosn to readme --- Makefile | 2 +- test_libs/pyspec/README.md | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1b7155625..4ee757f88 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ install_test: test: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); . venv/bin/activate; export PYTHONPATH="./"; \ - python -m pytest --cov=eth2spec.phase0.spec --cov=eth2spec.phase1.spec --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec -k transfer + python -m pytest --cov=eth2spec.phase0.spec --cov=eth2spec.phase1.spec --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec citest: $(PY_SPEC_ALL_TARGETS) cd $(PY_SPEC_DIR); mkdir -p test-reports/eth2spec; . venv/bin/activate; \ diff --git a/test_libs/pyspec/README.md b/test_libs/pyspec/README.md index 2c2226ee7..53750517d 100644 --- a/test_libs/pyspec/README.md +++ b/test_libs/pyspec/README.md @@ -28,7 +28,7 @@ These tests are sanity tests, to verify if the spec itself is consistent. #### Automated -Run `make test` from the root of the specs repository. +Run `make test` from the root of the specs repository (after running `make install_test` if have not before). #### Manual @@ -50,6 +50,10 @@ pytest --config=minimal eth2spec ``` Note the package-name, this is to locate the tests. +### How to view code coverage report + +Run `make open_cov` from the root of the specs repository after running `make test` to open the html code coverage report. + ## Contributing From d911236fbb3fffca524318d8016161688b0d3f1e Mon Sep 17 00:00:00 2001 From: terence tsao Date: Mon, 17 Jun 2019 14:19:17 -0700 Subject: [PATCH 23/25] Update slots.md --- specs/test_formats/sanity/slots.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/test_formats/sanity/slots.md b/specs/test_formats/sanity/slots.md index 81866d47b..eb0f336b4 100644 --- a/specs/test_formats/sanity/slots.md +++ b/specs/test_formats/sanity/slots.md @@ -8,7 +8,7 @@ Sanity tests to cover a series of one or more empty-slot transitions being proce description: string -- description of test case, purely for debugging purposes bls_setting: int -- see general test-format spec. pre: BeaconState -- state before running through the transitions. -slots: N -- amount of slots to process, N being a positive numer. +slots: N -- amount of slots to process, N being a positive number. post: BeaconState -- state after applying all the transitions. ``` From 207eb808a0cad10d0ec20b5fd0ae23004fd59705 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Jun 2019 15:19:44 -0600 Subject: [PATCH 24/25] split constants vs configuration --- configs/constant_presets/mainnet.yaml | 4 ---- configs/constant_presets/minimal.yaml | 4 ---- specs/core/0_beacon-chain.md | 21 ++++++++++++--------- specs/core/0_fork-choice.md | 4 ++-- specs/core/1_shard-data-chains.md | 9 +++++++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index c0b7c6e9c..892111ce0 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -25,8 +25,6 @@ SHUFFLE_ROUND_COUNT: 90 # --------------------------------------------------------------- # **TBD** DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890 -# 2**5 (= 32) -DEPOSIT_CONTRACT_TREE_DEPTH: 32 # Gwei values @@ -46,8 +44,6 @@ EFFECTIVE_BALANCE_INCREMENT: 1000000000 GENESIS_FORK_VERSION: 0x00000000 # 0, GENESIS_EPOCH is derived from this constant GENESIS_SLOT: 0 -# 2**64 - 1 -FAR_FUTURE_EPOCH: 18446744073709551615 BLS_WITHDRAWAL_PREFIX: 0 diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index cdd919927..5f4087d89 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -24,8 +24,6 @@ SHUFFLE_ROUND_COUNT: 10 # --------------------------------------------------------------- # **TBD** DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890 -# 2**5 (= 32) -DEPOSIT_CONTRACT_TREE_DEPTH: 32 # Gwei values @@ -45,8 +43,6 @@ EFFECTIVE_BALANCE_INCREMENT: 1000000000 GENESIS_FORK_VERSION: 0x00000000 # 0, GENESIS_EPOCH is derived from this constant GENESIS_SLOT: 0 -# 2**64 - 1 -FAR_FUTURE_EPOCH: 18446744073709551615 BLS_WITHDRAWAL_PREFIX: 0 diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 968098895..6f6b6e74e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -11,6 +11,7 @@ - [Notation](#notation) - [Terminology](#terminology) - [Constants](#constants) + - [Configuration](#configuration) - [Misc](#misc) - [Deposit contract](#deposit-contract) - [Gwei values](#gwei-values) @@ -152,7 +153,17 @@ Code snippets appearing in `this style` are to be interpreted as Python code. ## Constants -*Note*: The default mainnet values for the constants are included here for spec-design purposes. +The following values are (non-configurable) constants used throughout the specification. + +| Name | Value | +| - | - | +| `FAR_FUTURE_EPOCH` | `2**64 - 1` | +| `ZERO_HASH` | `b'\x00' * 32` | +| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | + +## Configuration + +*Note*: The default mainnet configuration values are included here for spec-design purposes. The different configurations for mainnet, testnets, and YAML-based testing can be found in the `configs/constant_presets/` directory. These configurations are updated for releases, but may be out of sync during `dev` changes. @@ -170,12 +181,6 @@ These configurations are updated for releases, but may be out of sync during `de * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) -### Deposit contract - -| Name | Value | -| - | - | -| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | - ### Gwei values | Name | Value | Unit | @@ -191,8 +196,6 @@ These configurations are updated for releases, but may be out of sync during `de | - | - | | `GENESIS_SLOT` | `0` | | `GENESIS_EPOCH` | `0` | -| `FAR_FUTURE_EPOCH` | `2**64 - 1` | -| `ZERO_HASH` | `b'\x00' * 32` | | `BLS_WITHDRAWAL_PREFIX` | `0` | ### Time parameters diff --git a/specs/core/0_fork-choice.md b/specs/core/0_fork-choice.md index 8103bbeb2..1910b6d04 100644 --- a/specs/core/0_fork-choice.md +++ b/specs/core/0_fork-choice.md @@ -9,7 +9,7 @@ - [Table of contents](#table-of-contents) - [Introduction](#introduction) - [Prerequisites](#prerequisites) - - [Constants](#constants) + - [Configuration](#configuration) - [Time parameters](#time-parameters) - [Beacon chain processing](#beacon-chain-processing) - [Beacon chain fork choice rule](#beacon-chain-fork-choice-rule) @@ -26,7 +26,7 @@ This document represents the specification for the beacon chain fork choice rule All terminology, constants, functions, and protocol mechanics defined in the [Phase 0 -- The Beacon Chain](./0_beacon-chain.md) doc are requisite for this document and used throughout. Please see the Phase 0 doc before continuing and use as a reference throughout. -## Constants +## Configuration ### Time parameters diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index a895b3c38..1b2b2b2da 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -9,8 +9,9 @@ - [Ethereum 2.0 Phase 1 -- Shard Data Chains](#ethereum-20-phase-1----shard-data-chains) - [Table of contents](#table-of-contents) - [Introduction](#introduction) - - [Constants](#constants) + - [Configuration](#configuration) - [Misc](#misc) + - [Initial values](#initial-values) - [Time parameters](#time-parameters) - [Signature domains](#signature-domains) - [Data structures](#data-structures) @@ -38,7 +39,7 @@ This document describes the shard data layer and the shard fork choice rule in Phase 1 of Ethereum 2.0. -## Constants +## Configuration ### Misc @@ -46,6 +47,10 @@ This document describes the shard data layer and the shard fork choice rule in P | - | - | | `BYTES_PER_SHARD_BLOCK_BODY` | `2**14` (= 16,384) | | `MAX_SHARD_ATTESTIONS` | `2**4` (= 16) | + +### Initial values + +| Name | Value | | `PHASE_1_FORK_EPOCH` | **TBD** | | `PHASE_1_FORK_SLOT` | **TBD** | | `GENESIS_SHARD_SLOT` | 0 | From 89d9d80b1c54fef13bf3135aa7fbcb534ce5e700 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Jun 2019 16:12:47 -0600 Subject: [PATCH 25/25] move BASE_REWARDS_PER_EPOCH to constants --- configs/constant_presets/mainnet.yaml | 2 -- configs/constant_presets/minimal.yaml | 2 -- specs/core/0_beacon-chain.md | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index 892111ce0..ed839fc7d 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -15,8 +15,6 @@ MAX_INDICES_PER_ATTESTATION: 4096 MIN_PER_EPOCH_CHURN_LIMIT: 4 # 2**16 (= 65,536) CHURN_LIMIT_QUOTIENT: 65536 -# Normalizes base rewards -BASE_REWARDS_PER_EPOCH: 5 # See issue 563 SHUFFLE_ROUND_COUNT: 90 diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index 5f4087d89..d631300e2 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -14,8 +14,6 @@ MAX_INDICES_PER_ATTESTATION: 4096 MIN_PER_EPOCH_CHURN_LIMIT: 4 # 2**16 (= 65,536) CHURN_LIMIT_QUOTIENT: 65536 -# Normalizes base rewards -BASE_REWARDS_PER_EPOCH: 5 # [customized] Faster, but unsecure. SHUFFLE_ROUND_COUNT: 10 diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6f6b6e74e..4a8e316ea 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -159,6 +159,7 @@ The following values are (non-configurable) constants used throughout the specif | - | - | | `FAR_FUTURE_EPOCH` | `2**64 - 1` | | `ZERO_HASH` | `b'\x00' * 32` | +| `BASE_REWARDS_PER_EPOCH` | `5` | | `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | ## Configuration @@ -176,7 +177,6 @@ These configurations are updated for releases, but may be out of sync during `de | `MAX_INDICES_PER_ATTESTATION` | `2**12` (= 4,096) | | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | -| `BASE_REWARDS_PER_EPOCH` | `5` | | `SHUFFLE_ROUND_COUNT` | `90` | * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)