Merge pull request #1428 from ethereum/phase0-simplify

Remove Shards/Crosslinks from Phase 0
This commit is contained in:
Danny Ryan 2019-10-28 14:07:39 +08:00 committed by GitHub
commit 364781b934
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 179 additions and 548 deletions

View File

@ -5,12 +5,12 @@
# Misc # Misc
# --------------------------------------------------------------- # ---------------------------------------------------------------
# 2**10 (= 1,024) # 2**6 (= 64)
SHARD_COUNT: 1024 MAX_COMMITTEES_PER_SLOT: 64
# 2**7 (= 128) # 2**7 (= 128)
TARGET_COMMITTEE_SIZE: 128 TARGET_COMMITTEE_SIZE: 128
# 2**12 (= 4,096) # 2**11 (= 2,048)
MAX_VALIDATORS_PER_COMMITTEE: 4096 MAX_VALIDATORS_PER_COMMITTEE: 2048
# 2**2 (= 4) # 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4 MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**16 (= 65,536) # 2**16 (= 65,536)
@ -51,12 +51,12 @@ BLS_WITHDRAWAL_PREFIX: 0x00
# Time parameters # Time parameters
# --------------------------------------------------------------- # ---------------------------------------------------------------
# 6 seconds 6 seconds # 12 seconds
SECONDS_PER_SLOT: 6 SECONDS_PER_SLOT: 12
# 2**0 (= 1) slots 6 seconds # 2**0 (= 1) slots 6 seconds
MIN_ATTESTATION_INCLUSION_DELAY: 1 MIN_ATTESTATION_INCLUSION_DELAY: 1
# 2**6 (= 64) slots 6.4 minutes # 2**5 (= 32) slots 6.4 minutes
SLOTS_PER_EPOCH: 64 SLOTS_PER_EPOCH: 32
# 2**0 (= 1) epochs 6.4 minutes # 2**0 (= 1) epochs 6.4 minutes
MIN_SEED_LOOKAHEAD: 1 MIN_SEED_LOOKAHEAD: 1
# 2**2 (= 4) epochs 25.6 minutes # 2**2 (= 4) epochs 25.6 minutes

View File

@ -4,12 +4,12 @@
# Misc # Misc
# --------------------------------------------------------------- # ---------------------------------------------------------------
# [customized] Just 8 shards for testing purposes # [customized] Just 4 committees for slot for testing purposes
SHARD_COUNT: 8 MAX_COMMITTEES_PER_SLOT: 4
# [customized] unsecure, but fast # [customized] unsecure, but fast
TARGET_COMMITTEE_SIZE: 4 TARGET_COMMITTEE_SIZE: 4
# 2**12 (= 4,096) # 2**11 (= 2,048)
MAX_VALIDATORS_PER_COMMITTEE: 4096 MAX_VALIDATORS_PER_COMMITTEE: 2048
# 2**2 (= 4) # 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4 MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**16 (= 65,536) # 2**16 (= 65,536)
@ -50,7 +50,7 @@ BLS_WITHDRAWAL_PREFIX: 0x00
# Time parameters # Time parameters
# --------------------------------------------------------------- # ---------------------------------------------------------------
# 6 seconds 6 seconds # [customized] Faster for testing purposes
SECONDS_PER_SLOT: 6 SECONDS_PER_SLOT: 6
# 2**0 (= 1) slots 6 seconds # 2**0 (= 1) slots 6 seconds
MIN_ATTESTATION_INCLUSION_DELAY: 1 MIN_ATTESTATION_INCLUSION_DELAY: 1

View File

@ -118,7 +118,7 @@ def apply_constants_preset(preset: Dict[str, Any]) -> None:
global_vars[k] = v global_vars[k] = v
# Deal with derived constants # Deal with derived constants
global_vars['GENESIS_EPOCH'] = compute_epoch_of_slot(GENESIS_SLOT) global_vars['GENESIS_EPOCH'] = compute_epoch_at_slot(GENESIS_SLOT)
# Initialize SSZ types again, to account for changed lengths # Initialize SSZ types again, to account for changed lengths
init_SSZ_types() init_SSZ_types()

View File

@ -25,7 +25,6 @@
- [`Fork`](#fork) - [`Fork`](#fork)
- [`Checkpoint`](#checkpoint) - [`Checkpoint`](#checkpoint)
- [`Validator`](#validator) - [`Validator`](#validator)
- [`Crosslink`](#crosslink)
- [`AttestationData`](#attestationdata) - [`AttestationData`](#attestationdata)
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
- [`IndexedAttestation`](#indexedattestation) - [`IndexedAttestation`](#indexedattestation)
@ -69,8 +68,8 @@
- [`compute_shuffled_index`](#compute_shuffled_index) - [`compute_shuffled_index`](#compute_shuffled_index)
- [`compute_proposer_index`](#compute_proposer_index) - [`compute_proposer_index`](#compute_proposer_index)
- [`compute_committee`](#compute_committee) - [`compute_committee`](#compute_committee)
- [`compute_epoch_of_slot`](#compute_epoch_of_slot) - [`compute_epoch_at_slot`](#compute_epoch_at_slot)
- [`compute_start_slot_of_epoch`](#compute_start_slot_of_epoch) - [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch)
- [`compute_activation_exit_epoch`](#compute_activation_exit_epoch) - [`compute_activation_exit_epoch`](#compute_activation_exit_epoch)
- [`compute_domain`](#compute_domain) - [`compute_domain`](#compute_domain)
- [Beacon state accessors](#beacon-state-accessors) - [Beacon state accessors](#beacon-state-accessors)
@ -82,12 +81,9 @@
- [`get_active_validator_indices`](#get_active_validator_indices) - [`get_active_validator_indices`](#get_active_validator_indices)
- [`get_validator_churn_limit`](#get_validator_churn_limit) - [`get_validator_churn_limit`](#get_validator_churn_limit)
- [`get_seed`](#get_seed) - [`get_seed`](#get_seed)
- [`get_committee_count`](#get_committee_count) - [`get_committee_count_at_slot`](#get_committee_count_at_slot)
- [`get_crosslink_committee`](#get_crosslink_committee) - [`get_beacon_committee`](#get_beacon_committee)
- [`get_start_shard`](#get_start_shard)
- [`get_shard_delta`](#get_shard_delta)
- [`get_beacon_proposer_index`](#get_beacon_proposer_index) - [`get_beacon_proposer_index`](#get_beacon_proposer_index)
- [`get_attestation_data_slot`](#get_attestation_data_slot)
- [`get_total_balance`](#get_total_balance) - [`get_total_balance`](#get_total_balance)
- [`get_total_active_balance`](#get_total_active_balance) - [`get_total_active_balance`](#get_total_active_balance)
- [`get_domain`](#get_domain) - [`get_domain`](#get_domain)
@ -105,7 +101,6 @@
- [Epoch processing](#epoch-processing) - [Epoch processing](#epoch-processing)
- [Helper functions](#helper-functions-1) - [Helper functions](#helper-functions-1)
- [Justification and finalization](#justification-and-finalization) - [Justification and finalization](#justification-and-finalization)
- [Crosslinks](#crosslinks)
- [Rewards and penalties](#rewards-and-penalties-1) - [Rewards and penalties](#rewards-and-penalties-1)
- [Registry updates](#registry-updates) - [Registry updates](#registry-updates)
- [Slashings](#slashings) - [Slashings](#slashings)
@ -129,7 +124,7 @@
This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain. This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain.
At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of validators. In the initial deployment phases of Ethereum 2.0, the only mechanism to become a validator is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a validator happens when Ethereum 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of validators. In the initial deployment phases of Ethereum 2.0, the only mechanism to become a validator is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a validator happens when Ethereum 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior.
The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block and proof-of-stake votes for a beacon block. A sufficient number of attestations for the same shard block create a "crosslink", confirming the shard segment up to that shard block into the beacon chain. Crosslinks also serve as infrastructure for asynchronous cross-shard communication. The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block (Phase 1) and proof-of-stake votes for a beacon block (Phase 0).
## Notation ## Notation
@ -143,7 +138,7 @@ We define the following Python custom types for type hinting and readability:
| - | - | - | | - | - | - |
| `Slot` | `uint64` | a slot number | | `Slot` | `uint64` | a slot number |
| `Epoch` | `uint64` | an epoch number | | `Epoch` | `uint64` | an epoch number |
| `Shard` | `uint64` | a shard number | | `CommitteeIndex` | `uint64` | a committee index at a slot |
| `ValidatorIndex` | `uint64` | a validator registry index | | `ValidatorIndex` | `uint64` | a validator registry index |
| `Gwei` | `uint64` | an amount in Gwei | | `Gwei` | `uint64` | an amount in Gwei |
| `Hash` | `Bytes32` | a hash | | `Hash` | `Bytes32` | a hash |
@ -160,7 +155,7 @@ The following values are (non-configurable) constants used throughout the specif
| Name | Value | | Name | Value |
| - | - | | - | - |
| `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` | | `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` |
| `BASE_REWARDS_PER_EPOCH` | `5` | | `BASE_REWARDS_PER_EPOCH` | `4` |
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | | `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
| `SECONDS_PER_DAY` | `86400` | | `SECONDS_PER_DAY` | `86400` |
| `JUSTIFICATION_BITS_LENGTH` | `4` | | `JUSTIFICATION_BITS_LENGTH` | `4` |
@ -174,16 +169,16 @@ The following values are (non-configurable) constants used throughout the specif
| Name | Value | | Name | Value |
| - | - | | - | - |
| `SHARD_COUNT` | `2**10` (= 1,024) | | `MAX_COMMITTEES_PER_SLOT` | `2**6` (= 64) |
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
| `MAX_VALIDATORS_PER_COMMITTEE` | `2**12` (= 4,096) | | `MAX_VALIDATORS_PER_COMMITTEE` | `2**11` (= 2,048) |
| `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) |
| `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) |
| `SHUFFLE_ROUND_COUNT` | `90` | | `SHUFFLE_ROUND_COUNT` | `90` |
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | | `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) |
| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | | `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) |
- 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.) - For the safety of committees, `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.)
### Gwei values ### Gwei values
@ -206,16 +201,15 @@ The following values are (non-configurable) constants used throughout the specif
| Name | Value | Unit | Duration | | Name | Value | Unit | Duration |
| - | - | :-: | :-: | | - | - | :-: | :-: |
| `SECONDS_PER_SLOT` | `6` | seconds | 6 seconds | | `SECONDS_PER_SLOT` | `12` | seconds | 12 seconds |
| `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 6 seconds | | `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 12 seconds |
| `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes | | `SLOTS_PER_EPOCH` | `2**5` (= 32) | slots | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes | | `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
| `MAX_SEED_LOOKAHEAD` | `2**2` (= 4) | epochs | 25.6 minutes | | `MAX_SEED_LOOKAHEAD` | `2**2` (= 4) | epochs | 25.6 minutes |
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours | | `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours | | `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours | | `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days | | `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
| `MAX_EPOCHS_PER_CROSSLINK` | `2**6` (= 64) | epochs | ~7 hours |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes | | `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes |
### State list lengths ### State list lengths
@ -305,29 +299,17 @@ class Validator(Container):
withdrawable_epoch: Epoch # When validator can withdraw or transfer funds withdrawable_epoch: Epoch # When validator can withdraw or transfer funds
``` ```
#### `Crosslink`
```python
class Crosslink(Container):
shard: Shard
parent_root: Hash
# Crosslinking data
start_epoch: Epoch
end_epoch: Epoch
data_root: Hash
```
#### `AttestationData` #### `AttestationData`
```python ```python
class AttestationData(Container): class AttestationData(Container):
slot: Slot
index: CommitteeIndex
# LMD GHOST vote # LMD GHOST vote
beacon_block_root: Hash beacon_block_root: Hash
# FFG vote # FFG vote
source: Checkpoint source: Checkpoint
target: Checkpoint target: Checkpoint
# Crosslink vote
crosslink: Crosslink
``` ```
#### `AttestationDataAndCustodyBit` #### `AttestationDataAndCustodyBit`
@ -335,7 +317,7 @@ class AttestationData(Container):
```python ```python
class AttestationDataAndCustodyBit(Container): class AttestationDataAndCustodyBit(Container):
data: AttestationData data: AttestationData
custody_bit: bit # Challengeable bit (SSZ-bool, 1 byte) for the custody of crosslink data custody_bit: bit # Challengeable bit (SSZ-bool, 1 byte) for the custody of shard data
``` ```
#### `IndexedAttestation` #### `IndexedAttestation`
@ -506,17 +488,13 @@ class BeaconState(Container):
# Registry # Registry
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
# Shuffling # Randomness
start_shard: Shard
randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR]
# Slashings # Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
# Attestations # Attestations
previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH] previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH] current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
# Crosslinks
previous_crosslinks: Vector[Crosslink, SHARD_COUNT] # Previous epoch snapshot
current_crosslinks: Vector[Crosslink, SHARD_COUNT]
# Finality # Finality
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
previous_justified_checkpoint: Checkpoint # Previous epoch snapshot previous_justified_checkpoint: Checkpoint # Previous epoch snapshot
@ -752,20 +730,20 @@ def compute_committee(indices: Sequence[ValidatorIndex],
return [indices[compute_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)] return [indices[compute_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
``` ```
#### `compute_epoch_of_slot` #### `compute_epoch_at_slot`
```python ```python
def compute_epoch_of_slot(slot: Slot) -> Epoch: def compute_epoch_at_slot(slot: Slot) -> Epoch:
""" """
Return the epoch number of ``slot``. Return the epoch number at ``slot``.
""" """
return Epoch(slot // SLOTS_PER_EPOCH) return Epoch(slot // SLOTS_PER_EPOCH)
``` ```
#### `compute_start_slot_of_epoch` #### `compute_start_slot_at_epoch`
```python ```python
def compute_start_slot_of_epoch(epoch: Epoch) -> Slot: def compute_start_slot_at_epoch(epoch: Epoch) -> Slot:
""" """
Return the start slot of ``epoch``. Return the start slot of ``epoch``.
""" """
@ -801,7 +779,7 @@ def get_current_epoch(state: BeaconState) -> Epoch:
""" """
Return the current epoch. Return the current epoch.
""" """
return compute_epoch_of_slot(state.slot) return compute_epoch_at_slot(state.slot)
``` ```
#### `get_previous_epoch` #### `get_previous_epoch`
@ -822,7 +800,7 @@ def get_block_root(state: BeaconState, epoch: Epoch) -> Hash:
""" """
Return the block root at the start of a recent ``epoch``. Return the block root at the start of a recent ``epoch``.
""" """
return get_block_root_at_slot(state, compute_start_slot_of_epoch(epoch)) return get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch))
``` ```
#### `get_block_root_at_slot` #### `get_block_root_at_slot`
@ -878,61 +856,37 @@ def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Hash:
return hash(domain_type + int_to_bytes(epoch, length=8) + mix) return hash(domain_type + int_to_bytes(epoch, length=8) + mix)
``` ```
#### `get_committee_count` #### `get_committee_count_at_slot`
```python ```python
def get_committee_count(state: BeaconState, epoch: Epoch) -> uint64: def get_committee_count_at_slot(state: BeaconState, slot: Slot) -> uint64:
""" """
Return the number of committees at ``epoch``. Return the number of committees at ``slot``.
""" """
committees_per_slot = max(1, min( epoch = compute_epoch_at_slot(slot)
SHARD_COUNT // SLOTS_PER_EPOCH, return max(1, min(
MAX_COMMITTEES_PER_SLOT,
len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE,
)) ))
return committees_per_slot * SLOTS_PER_EPOCH
``` ```
#### `get_crosslink_committee` #### `get_beacon_committee`
```python ```python
def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> Sequence[ValidatorIndex]: def get_beacon_committee(state: BeaconState, slot: Slot, index: CommitteeIndex) -> Sequence[ValidatorIndex]:
""" """
Return the crosslink committee at ``epoch`` for ``shard``. Return the beacon committee at ``slot`` for ``index``.
""" """
epoch = compute_epoch_at_slot(slot)
committees_per_slot = get_committee_count_at_slot(state, slot)
return compute_committee( return compute_committee(
indices=get_active_validator_indices(state, epoch), indices=get_active_validator_indices(state, epoch),
seed=get_seed(state, epoch, DOMAIN_BEACON_ATTESTER), seed=get_seed(state, epoch, DOMAIN_BEACON_ATTESTER),
index=(shard + SHARD_COUNT - get_start_shard(state, epoch)) % SHARD_COUNT, index=(slot % SLOTS_PER_EPOCH) * committees_per_slot + index,
count=get_committee_count(state, epoch), count=committees_per_slot * SLOTS_PER_EPOCH,
) )
``` ```
#### `get_start_shard`
```python
def get_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
"""
Return the start shard of the 0th committee at ``epoch``.
"""
assert epoch <= get_current_epoch(state) + 1
check_epoch = Epoch(get_current_epoch(state) + 1)
shard = Shard((state.start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT)
while check_epoch > epoch:
check_epoch -= Epoch(1)
shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT)
return shard
```
#### `get_shard_delta`
```python
def get_shard_delta(state: BeaconState, epoch: Epoch) -> uint64:
"""
Return the number of shards to increment ``state.start_shard`` at ``epoch``.
"""
return min(get_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH)
```
#### `get_beacon_proposer_index` #### `get_beacon_proposer_index`
```python ```python
@ -946,18 +900,6 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
return compute_proposer_index(state, indices, seed) return compute_proposer_index(state, indices, seed)
``` ```
#### `get_attestation_data_slot`
```python
def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot:
"""
Return the slot corresponding to the attestation ``data``.
"""
committee_count = get_committee_count(state, data.target.epoch)
offset = (data.crosslink.shard + SHARD_COUNT - get_start_shard(state, data.target.epoch)) % SHARD_COUNT
return Slot(compute_start_slot_of_epoch(data.target.epoch) + offset // (committee_count // SLOTS_PER_EPOCH))
```
#### `get_total_balance` #### `get_total_balance`
```python ```python
@ -1019,7 +961,7 @@ def get_attesting_indices(state: BeaconState,
""" """
Return the set of attesting indices corresponding to ``data`` and ``bits``. Return the set of attesting indices corresponding to ``data`` and ``bits``.
""" """
committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard) committee = get_beacon_committee(state, data.slot, data.index)
return set(index for i, index in enumerate(committee) if bits[i]) return set(index for i, index in enumerate(committee) if bits[i])
``` ```
@ -1199,7 +1141,6 @@ def process_slot(state: BeaconState) -> None:
```python ```python
def process_epoch(state: BeaconState) -> None: def process_epoch(state: BeaconState) -> None:
process_justification_and_finalization(state) process_justification_and_finalization(state)
process_crosslinks(state)
process_rewards_and_penalties(state) process_rewards_and_penalties(state)
process_registry_updates(state) process_registry_updates(state)
# @process_reveal_deadlines # @process_reveal_deadlines
@ -1230,7 +1171,7 @@ def get_matching_target_attestations(state: BeaconState, epoch: Epoch) -> Sequen
def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]: def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
return [ return [
a for a in get_matching_source_attestations(state, epoch) a for a in get_matching_source_attestations(state, epoch)
if a.data.beacon_block_root == get_block_root_at_slot(state, get_attestation_data_slot(state, a.data)) if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot)
] ]
``` ```
@ -1248,23 +1189,6 @@ def get_attesting_balance(state: BeaconState, attestations: Sequence[PendingAtte
return get_total_balance(state, get_unslashed_attesting_indices(state, attestations)) return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
``` ```
```python
def get_winning_crosslink_and_attesting_indices(state: BeaconState,
epoch: Epoch,
shard: Shard) -> Tuple[Crosslink, Set[ValidatorIndex]]:
attestations = [a for a in get_matching_source_attestations(state, epoch) if a.data.crosslink.shard == shard]
crosslinks = filter(
lambda c: hash_tree_root(state.current_crosslinks[shard]) in (c.parent_root, hash_tree_root(c)),
[a.data.crosslink for a in attestations]
)
# Winning crosslink has the crosslink data root with the most balance voting for it (ties broken lexicographically)
winning_crosslink = max(crosslinks, key=lambda c: (
get_attesting_balance(state, [a for a in attestations if a.data.crosslink == c]), c.data_root
), default=Crosslink())
winning_attestations = [a for a in attestations if a.data.crosslink == winning_crosslink]
return winning_crosslink, get_unslashed_attesting_indices(state, winning_attestations)
```
#### Justification and finalization #### Justification and finalization
```python ```python
@ -1308,20 +1232,6 @@ def process_justification_and_finalization(state: BeaconState) -> None:
state.finalized_checkpoint = old_current_justified_checkpoint state.finalized_checkpoint = old_current_justified_checkpoint
``` ```
#### Crosslinks
```python
def process_crosslinks(state: BeaconState) -> None:
state.previous_crosslinks = [c for c in state.current_crosslinks]
for epoch in (get_previous_epoch(state), get_current_epoch(state)):
for offset in range(get_committee_count(state, epoch)):
shard = Shard((get_start_shard(state, epoch) + offset) % SHARD_COUNT)
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee):
state.current_crosslinks[shard] = winning_crosslink
```
#### Rewards and penalties #### Rewards and penalties
```python ```python
@ -1382,36 +1292,15 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence
return rewards, penalties return rewards, penalties
``` ```
```python
def get_crosslink_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
rewards = [Gwei(0) for _ in range(len(state.validators))]
penalties = [Gwei(0) for _ in range(len(state.validators))]
epoch = get_previous_epoch(state)
for offset in range(get_committee_count(state, epoch)):
shard = Shard((get_start_shard(state, epoch) + offset) % SHARD_COUNT)
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
attesting_balance = get_total_balance(state, attesting_indices)
committee_balance = get_total_balance(state, crosslink_committee)
for index in crosslink_committee:
base_reward = get_base_reward(state, index)
if index in attesting_indices:
rewards[index] += base_reward * attesting_balance // committee_balance
else:
penalties[index] += base_reward
return rewards, penalties
```
```python ```python
def process_rewards_and_penalties(state: BeaconState) -> None: def process_rewards_and_penalties(state: BeaconState) -> None:
if get_current_epoch(state) == GENESIS_EPOCH: if get_current_epoch(state) == GENESIS_EPOCH:
return return
rewards1, penalties1 = get_attestation_deltas(state) rewards, penalties = get_attestation_deltas(state)
rewards2, penalties2 = get_crosslink_deltas(state)
for index in range(len(state.validators)): for index in range(len(state.validators)):
increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index]) increase_balance(state, ValidatorIndex(index), rewards[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index]) decrease_balance(state, ValidatorIndex(index), penalties[index])
``` ```
#### Registry updates #### Registry updates
@ -1479,8 +1368,6 @@ def process_final_updates(state: BeaconState) -> None:
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
historical_batch = HistoricalBatch(block_roots=state.block_roots, state_roots=state.state_roots) historical_batch = HistoricalBatch(block_roots=state.block_roots, state_roots=state.state_roots)
state.historical_roots.append(hash_tree_root(historical_batch)) state.historical_roots.append(hash_tree_root(historical_batch))
# Update start shard
state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
# Rotate current/previous epoch attestations # Rotate current/previous epoch attestations
state.previous_epoch_attestations = state.current_epoch_attestations state.previous_epoch_attestations = state.current_epoch_attestations
state.current_epoch_attestations = [] state.current_epoch_attestations = []
@ -1576,7 +1463,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla
assert is_slashable_validator(proposer, get_current_epoch(state)) assert is_slashable_validator(proposer, get_current_epoch(state))
# Signatures are valid # Signatures are valid
for header in (proposer_slashing.header_1, proposer_slashing.header_2): for header in (proposer_slashing.header_1, proposer_slashing.header_2):
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_of_slot(header.slot)) domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot))
assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain) assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain)
slash_validator(state, proposer_slashing.proposer_index) slash_validator(state, proposer_slashing.proposer_index)
@ -1607,37 +1494,27 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla
```python ```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None: def process_attestation(state: BeaconState, attestation: Attestation) -> None:
data = attestation.data data = attestation.data
assert data.crosslink.shard < SHARD_COUNT assert data.index < get_committee_count_at_slot(state, data.slot)
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
attestation_slot = get_attestation_data_slot(state, data) committee = get_beacon_committee(state, data.slot, data.index)
assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH
committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard)
assert len(attestation.aggregation_bits) == len(attestation.custody_bits) == len(committee) assert len(attestation.aggregation_bits) == len(attestation.custody_bits) == len(committee)
pending_attestation = PendingAttestation( pending_attestation = PendingAttestation(
data=data, data=data,
aggregation_bits=attestation.aggregation_bits, aggregation_bits=attestation.aggregation_bits,
inclusion_delay=state.slot - attestation_slot, inclusion_delay=state.slot - data.slot,
proposer_index=get_beacon_proposer_index(state), proposer_index=get_beacon_proposer_index(state),
) )
if data.target.epoch == get_current_epoch(state): if data.target.epoch == get_current_epoch(state):
assert data.source == state.current_justified_checkpoint assert data.source == state.current_justified_checkpoint
parent_crosslink = state.current_crosslinks[data.crosslink.shard]
state.current_epoch_attestations.append(pending_attestation) state.current_epoch_attestations.append(pending_attestation)
else: else:
assert data.source == state.previous_justified_checkpoint assert data.source == state.previous_justified_checkpoint
parent_crosslink = state.previous_crosslinks[data.crosslink.shard]
state.previous_epoch_attestations.append(pending_attestation) state.previous_epoch_attestations.append(pending_attestation)
# Check crosslink against expected parent crosslink
assert data.crosslink.parent_root == hash_tree_root(parent_crosslink)
assert data.crosslink.start_epoch == parent_crosslink.end_epoch
assert data.crosslink.end_epoch == min(data.target.epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK)
assert data.crosslink.data_root == Bytes32() # [to be removed in phase 1]
# Check signature # Check signature
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
``` ```

View File

@ -118,7 +118,7 @@ def get_latest_attesting_balance(store: Store, root: Hash) -> Gwei:
def get_head(store: Store) -> Hash: def get_head(store: Store) -> Hash:
# Execute the LMD-GHOST fork choice # Execute the LMD-GHOST fork choice
head = store.justified_checkpoint.root head = store.justified_checkpoint.root
justified_slot = compute_start_slot_of_epoch(store.justified_checkpoint.epoch) justified_slot = compute_start_slot_at_epoch(store.justified_checkpoint.epoch)
while True: while True:
children = [ children = [
root for root in store.blocks.keys() root for root in store.blocks.keys()
@ -156,7 +156,7 @@ def on_block(store: Store, block: BeaconBlock) -> None:
store.finalized_checkpoint.root store.finalized_checkpoint.root
) )
# Check that block is later than the finalized epoch slot # Check that block is later than the finalized epoch slot
assert block.slot > compute_start_slot_of_epoch(store.finalized_checkpoint.epoch) assert block.slot > compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
# Check the block is valid and compute the post-state # Check the block is valid and compute the post-state
state = state_transition(pre_state, block) state = state_transition(pre_state, block)
# Add new state for this block to the store # Add new state for this block to the store
@ -182,18 +182,17 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives # Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
base_state = store.block_states[target.root].copy() base_state = store.block_states[target.root].copy()
assert store.time >= base_state.genesis_time + compute_start_slot_of_epoch(target.epoch) * SECONDS_PER_SLOT assert store.time >= base_state.genesis_time + compute_start_slot_at_epoch(target.epoch) * SECONDS_PER_SLOT
# Store target checkpoint state if not yet seen # Store target checkpoint state if not yet seen
if target not in store.checkpoint_states: if target not in store.checkpoint_states:
process_slots(base_state, compute_start_slot_of_epoch(target.epoch)) process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
store.checkpoint_states[target] = base_state store.checkpoint_states[target] = base_state
target_state = store.checkpoint_states[target] target_state = store.checkpoint_states[target]
# Attestations can only affect the fork choice of subsequent slots. # Attestations can only affect the fork choice of subsequent slots.
# Delay consideration in the fork choice until their slot is in the past. # Delay consideration in the fork choice until their slot is in the past.
attestation_slot = get_attestation_data_slot(target_state, attestation.data) assert store.time >= (attestation.data.slot + 1) * SECONDS_PER_SLOT
assert store.time >= (attestation_slot + 1) * SECONDS_PER_SLOT
# Get state at the `target` to validate attestation and calculate the committees # Get state at the `target` to validate attestation and calculate the committees
indexed_attestation = get_indexed_attestation(target_state, attestation) indexed_attestation = get_indexed_attestation(target_state, attestation)

View File

@ -9,6 +9,7 @@
- [Configuration](#configuration) - [Configuration](#configuration)
- [Containers](#containers) - [Containers](#containers)
- [`CompactCommittee`](#compactcommittee) - [`CompactCommittee`](#compactcommittee)
- [`ShardReceiptDelta`](#shardreceiptdelta)
- [`ShardReceiptProof`](#shardreceiptproof) - [`ShardReceiptProof`](#shardreceiptproof)
- [Helper functions](#helper-functions) - [Helper functions](#helper-functions)
- [`pack_compact_validator`](#pack_compact_validator) - [`pack_compact_validator`](#pack_compact_validator)
@ -203,7 +204,7 @@ class BeaconState(Container):
``` ```
`period_committee_roots` values are initialized to `Bytes32()` (empty bytes value). `period_committee_roots` values are initialized to `Bytes32()` (empty bytes value).
`next_shard_receipt_period` values are initialized to `compute_epoch_of_slot(PHASE_1_FORK_SLOT) // EPOCHS_PER_SHARD_PERIOD`. `next_shard_receipt_period` values are initialized to `compute_epoch_at_slot(PHASE_1_FORK_SLOT) // EPOCHS_PER_SHARD_PERIOD`.
#### `BeaconBlockBody` #### `BeaconBlockBody`

View File

@ -81,6 +81,7 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| - | - | | - | - |
| `BLS12_381_Q` | `4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787` | | `BLS12_381_Q` | `4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787` |
| `MINOR_REWARD_QUOTIENT` | `2**8` (= 256) | | `MINOR_REWARD_QUOTIENT` | `2**8` (= 256) |
| `MAX_EPOCHS_PER_CROSSLINK` | `2**6` (= 64) | epochs | ~7 hours |
### Custody game parameters ### Custody game parameters
@ -335,7 +336,7 @@ def legendre_bit(a: int, q: int) -> int:
return 0 return 0
``` ```
### ```custody_subchunkify``` ### `custody_subchunkify`
Given one proof of custody chunk, returns the proof of custody subchunks of the correct sizes. Given one proof of custody chunk, returns the proof of custody subchunks of the correct sizes.
@ -546,7 +547,7 @@ def process_chunk_challenge(state: BeaconState, challenge: CustodyChunkChallenge
# Verify the attestation # Verify the attestation
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, challenge.attestation)) assert is_valid_indexed_attestation(state, get_indexed_attestation(state, challenge.attestation))
# Verify it is not too late to challenge # Verify it is not too late to challenge
assert (compute_epoch_of_slot(challenge.attestation.data.slot) assert (compute_epoch_at_slot(challenge.attestation.data.slot)
>= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY) >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY)
responder = state.validators[challenge.responder_index] responder = state.validators[challenge.responder_index]
assert responder.exit_epoch >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY assert responder.exit_epoch >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
@ -623,7 +624,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) ->
chunk_count = get_custody_chunk_count(attestation.data.crosslink) chunk_count = get_custody_chunk_count(attestation.data.crosslink)
assert chunk_count == len(challenge.chunk_bits) assert chunk_count == len(challenge.chunk_bits)
# Verify custody bit is incorrect # Verify custody bit is incorrect
committee = get_crosslink_committee(state, epoch, shard) committee = get_beacon_committee(state, epoch, shard)
custody_bit = attestation.custody_bits[committee.index(challenge.responder_index)] custody_bit = attestation.custody_bits[committee.index(challenge.responder_index)]
assert custody_bit != get_chunk_bits_root(challenge.chunk_bits) assert custody_bit != get_chunk_bits_root(challenge.chunk_bits)
# Add new bit challenge record # Add new bit challenge record

View File

@ -18,10 +18,11 @@
- [Rewards and penalties](#rewards-and-penalties) - [Rewards and penalties](#rewards-and-penalties)
- [Signature domain types](#signature-domain-types) - [Signature domain types](#signature-domain-types)
- [Containers](#containers) - [Containers](#containers)
- [`Crosslink`](#crosslink)
- [`ShardBlock`](#shardblock) - [`ShardBlock`](#shardblock)
- [`ShardBlockHeader`](#shardblockheader) - [`ShardBlockHeader`](#shardblockheader)
- [`ShardState`](#shardstate) - [`ShardState`](#shardstate)
- [`ShardAttestationData`](#ShardAttestationData) - [`ShardAttestationData`](#shardattestationdata)
- [Helper functions](#helper-functions) - [Helper functions](#helper-functions)
- [Misc](#misc-1) - [Misc](#misc-1)
- [`compute_epoch_of_shard_slot`](#compute_epoch_of_shard_slot) - [`compute_epoch_of_shard_slot`](#compute_epoch_of_shard_slot)
@ -53,6 +54,7 @@ This document describes the shard transition function (data layer only) and the
| Name | SSZ equivalent | Description | | Name | SSZ equivalent | Description |
| - | - | - | | - | - | - |
| `Shard` | `uint64` | a shard number |
| `ShardSlot` | `uint64` | a shard slot number | | `ShardSlot` | `uint64` | a shard slot number |
## Configuration ## Configuration
@ -61,6 +63,7 @@ This document describes the shard transition function (data layer only) and the
| Name | Value | | Name | Value |
| - | - | | - | - |
| `SHARD_COUNT` | `2**10` (= 1,024) |
| `MIN_BLOCK_BODY_PRICE` | `2**0` (= 1) | | `MIN_BLOCK_BODY_PRICE` | `2**0` (= 1) |
| `MAX_PERIOD_COMMITTEE_SIZE` | `2**7` (= 128) | | `MAX_PERIOD_COMMITTEE_SIZE` | `2**7` (= 128) |
| `SHARD_HEADER_SIZE` | `2**10` (= 1024) | | `SHARD_HEADER_SIZE` | `2**10` (= 1024) |
@ -101,6 +104,14 @@ This document describes the shard transition function (data layer only) and the
## Containers ## Containers
### `Crosslink`
```python
# Crosslink is a placeholder to appease the build script until phase 1 is reworked
class Crosslink(Container):
shard: Shard
```
### `ShardBlock` ### `ShardBlock`
```python ```python

View File

@ -84,7 +84,7 @@ def get_persistent_committee_pubkeys_and_balances(memory: LightClientMemory,
""" """
Return pubkeys and balances for the persistent committee at ``epoch``. Return pubkeys and balances for the persistent committee at ``epoch``.
""" """
current_period = compute_epoch_of_slot(memory.header.slot) // EPOCHS_PER_SHARD_PERIOD current_period = compute_epoch_at_slot(memory.header.slot) // EPOCHS_PER_SHARD_PERIOD
next_period = epoch // EPOCHS_PER_SHARD_PERIOD next_period = epoch // EPOCHS_PER_SHARD_PERIOD
assert next_period in (current_period, current_period + 1) assert next_period in (current_period, current_period + 1)
if next_period == current_period: if next_period == current_period:
@ -114,7 +114,7 @@ The state of a light client is stored in a `memory` object of type `LightClientM
```python ```python
def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None: def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None:
# Verify the update does not skip a period # Verify the update does not skip a period
current_period = compute_epoch_of_slot(memory.header.slot) // EPOCHS_PER_SHARD_PERIOD current_period = compute_epoch_at_slot(memory.header.slot) // EPOCHS_PER_SHARD_PERIOD
next_epoch = compute_epoch_of_shard_slot(update.header.slot) next_epoch = compute_epoch_of_shard_slot(update.header.slot)
next_period = next_epoch // EPOCHS_PER_SHARD_PERIOD next_period = next_epoch // EPOCHS_PER_SHARD_PERIOD
assert next_period in (current_period, current_period + 1) assert next_period in (current_period, current_period + 1)

View File

@ -38,7 +38,6 @@ The provided pre-state is already transitioned to just before the specific sub-t
Sub-transitions: Sub-transitions:
- `justification_and_finalization` - `justification_and_finalization`
- `crosslinks`
- *`rewards_and_penalties` - planned testing extension* - *`rewards_and_penalties` - planned testing extension*
- `registry_updates` - `registry_updates`
- `slashings` - `slashings`

View File

@ -41,7 +41,6 @@
- [Attestation data](#attestation-data) - [Attestation data](#attestation-data)
- [LMD GHOST vote](#lmd-ghost-vote) - [LMD GHOST vote](#lmd-ghost-vote)
- [FFG vote](#ffg-vote) - [FFG vote](#ffg-vote)
- [Crosslink vote](#crosslink-vote)
- [Construct attestation](#construct-attestation) - [Construct attestation](#construct-attestation)
- [Data](#data) - [Data](#data)
- [Aggregation bits](#aggregation-bits) - [Aggregation bits](#aggregation-bits)
@ -136,28 +135,25 @@ A validator can get committee assignments for a given epoch using the following
```python ```python
def get_committee_assignment(state: BeaconState, def get_committee_assignment(state: BeaconState,
epoch: Epoch, epoch: Epoch,
validator_index: ValidatorIndex) -> Optional[Tuple[Sequence[ValidatorIndex], Shard, Slot]]: validator_index: ValidatorIndex
) -> Optional[Tuple[Sequence[ValidatorIndex], CommitteeIndex, Slot]]:
""" """
Return the committee assignment in the ``epoch`` for ``validator_index``. Return the committee assignment in the ``epoch`` for ``validator_index``.
``assignment`` returned is a tuple of the following form: ``assignment`` returned is a tuple of the following form:
* ``assignment[0]`` is the list of validators in the committee * ``assignment[0]`` is the list of validators in the committee
* ``assignment[1]`` is the shard to which the committee is assigned * ``assignment[1]`` is the index to which the committee is assigned
* ``assignment[2]`` is the slot at which the committee is assigned * ``assignment[2]`` is the slot at which the committee is assigned
Return None if no assignment. Return None if no assignment.
""" """
next_epoch = get_current_epoch(state) + 1 next_epoch = get_current_epoch(state) + 1
assert epoch <= next_epoch assert epoch <= next_epoch
committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH start_slot = compute_start_slot_at_epoch(epoch)
start_slot = compute_start_slot_of_epoch(epoch)
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH): for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH) for index in range(get_committee_count_at_slot(state, Slot(slot))):
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT committee = get_beacon_committee(state, Slot(slot), CommitteeIndex(index))
for i in range(committees_per_slot):
shard = Shard((slot_start_shard + i) % SHARD_COUNT)
committee = get_crosslink_committee(state, epoch, shard)
if validator_index in committee: if validator_index in committee:
return committee, shard, Slot(slot) return committee, CommitteeIndex(index), Slot(slot)
return None return None
``` ```
@ -171,13 +167,13 @@ def is_proposer(state: BeaconState,
*Note*: To see if a validator is assigned to propose during the slot, the beacon state must be in the epoch in question. At the epoch boundaries, the validator must run an epoch transition into the epoch to successfully check the proposal assignment of the first slot. *Note*: To see if a validator is assigned to propose during the slot, the beacon state must be in the epoch in question. At the epoch boundaries, the validator must run an epoch transition into the epoch to successfully check the proposal assignment of the first slot.
*Note*: `BeaconBlock` proposal is distinct from crosslink committee assignment, and in a given epoch each responsibility might occur at different a different slot. *Note*: `BeaconBlock` proposal is distinct from beacon committee assignment, and in a given epoch each responsibility might occur at different a different slot.
### Lookahead ### Lookahead
The beacon chain shufflings are designed to provide a minimum of 1 epoch lookahead on the validator's upcoming committee assignments for attesting dictated by the shuffling and slot. Note that this lookahead does not apply to proposing, which must be checked during the epoch in question. The beacon chain shufflings are designed to provide a minimum of 1 epoch lookahead on the validator's upcoming committee assignments for attesting dictated by the shuffling and slot. Note that this lookahead does not apply to proposing, which must be checked during the epoch in question.
`get_committee_assignment` should be called at the start of each epoch to get the assignment for the next epoch (`current_epoch + 1`). A validator should plan for future assignments by noting at which future slot they will have to attest and also which shard they should begin syncing (in Phase 1+). `get_committee_assignment` should be called at the start of each epoch to get the assignment for the next epoch (`current_epoch + 1`). A validator should plan for future assignments by noting at which future slot they will have to attest.
Specifically, a validator should call `get_committee_assignment(state, next_epoch, validator_index)` when checking for next epoch assignments. Specifically, a validator should call `get_committee_assignment(state, next_epoch, validator_index)` when checking for next epoch assignments.
@ -215,8 +211,8 @@ Set `block.randao_reveal = epoch_signature` where `epoch_signature` is obtained
```python ```python
def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature: def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature:
domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_of_slot(block.slot)) domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot))
return bls_sign(privkey, hash_tree_root(compute_epoch_of_slot(block.slot)), domain) return bls_sign(privkey, hash_tree_root(compute_epoch_at_slot(block.slot)), domain)
``` ```
##### Eth1 Data ##### Eth1 Data
@ -249,7 +245,7 @@ Set `header.signature = block_signature` where `block_signature` is obtained fro
```python ```python
def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature:
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_of_slot(header.slot)) domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot))
return bls_sign(privkey, signing_root(header), domain) return bls_sign(privkey, signing_root(header), domain)
``` ```
@ -279,7 +275,7 @@ Up to `MAX_VOLUNTARY_EXITS`, [`VoluntaryExit`](../core/0_beacon-chain.md#volunta
### Attestations ### Attestations
A validator is expected to create, sign, and broadcast an attestation during each epoch. The `committee`, assigned `shard`, and assigned `slot` for which the validator performs this role during an epoch are defined by `get_committee_assignment(state, epoch, validator_index)`. A validator is expected to create, sign, and broadcast an attestation during each epoch. The `committee`, assigned `index`, and assigned `slot` for which the validator performs this role during an epoch are defined by `get_committee_assignment(state, epoch, validator_index)`.
A validator should create and broadcast the attestation halfway through the `slot` during which the validator is assigned―that is, `SECONDS_PER_SLOT * 0.5` seconds after the start of `slot`. A validator should create and broadcast the attestation halfway through the `slot` during which the validator is assigned―that is, `SECONDS_PER_SLOT * 0.5` seconds after the start of `slot`.
@ -290,6 +286,11 @@ First, the validator should construct `attestation_data`, an [`AttestationData`]
- Let `head_block` be the result of running the fork choice during the assigned slot. - Let `head_block` be the result of running the fork choice during the assigned slot.
- Let `head_state` be the state of `head_block` processed through any empty slots up to the assigned slot using `process_slots(state, slot)`. - Let `head_state` be the state of `head_block` processed through any empty slots up to the assigned slot using `process_slots(state, slot)`.
##### General
* Set `attestation_data.slot = slot` where `slot` is the assigned slot.
* Set `attestation_data.index = index` where `index` is the index associated with the validator's committee.
##### LMD GHOST vote ##### LMD GHOST vote
Set `attestation_data.beacon_block_root = signing_root(head_block)`. Set `attestation_data.beacon_block_root = signing_root(head_block)`.
@ -301,20 +302,9 @@ Set `attestation_data.beacon_block_root = signing_root(head_block)`.
*Note*: `epoch_boundary_block_root` can be looked up in the state using: *Note*: `epoch_boundary_block_root` can be looked up in the state using:
- Let `start_slot = compute_start_slot_of_epoch(get_current_epoch(head_state))`. - Let `start_slot = compute_start_slot_at_epoch(get_current_epoch(head_state))`.
- Let `epoch_boundary_block_root = signing_root(head_block) if start_slot == head_state.slot else get_block_root(state, start_slot)`. - Let `epoch_boundary_block_root = signing_root(head_block) if start_slot == head_state.slot else get_block_root(state, start_slot)`.
##### Crosslink vote
Construct `attestation_data.crosslink` via the following.
- Set `attestation_data.crosslink.shard = shard` where `shard` is the shard associated with the validator's committee.
- Let `parent_crosslink = head_state.current_crosslinks[shard]`.
- Set `attestation_data.crosslink.start_epoch = parent_crosslink.end_epoch`.
- Set `attestation_data.crosslink.end_epoch = min(attestation_data.target.epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK)`.
- Set `attestation_data.crosslink.parent_root = hash_tree_root(head_state.current_crosslinks[shard])`.
- Set `attestation_data.crosslink.data_root = ZERO_HASH`. *Note*: This is a stub for Phase 0.
#### Construct attestation #### Construct attestation
Next, the validator creates `attestation`, an [`Attestation`](../core/0_beacon-chain.md#attestation) object. Next, the validator creates `attestation`, an [`Attestation`](../core/0_beacon-chain.md#attestation) object.
@ -364,7 +354,7 @@ To avoid "proposer slashings", a validator must not sign two conflicting [`Beaco
Specifically, when signing a `BeaconBlock`, a validator should perform the following steps in the following order: Specifically, when signing a `BeaconBlock`, a validator should perform the following steps in the following order:
1. Save a record to hard disk that a beacon block has been signed for the `epoch=compute_epoch_of_slot(block.slot)`. 1. Save a record to hard disk that a beacon block has been signed for the `epoch=compute_epoch_at_slot(block.slot)`.
2. Generate and broadcast the block. 2. Generate and broadcast the block.
If the software crashes at some point within this routine, then when the validator comes back online, the hard disk has the record of the *potentially* signed/broadcast block and can effectively avoid slashing. If the software crashes at some point within this routine, then when the validator comes back online, the hard disk has the record of the *potentially* signed/broadcast block and can effectively avoid slashing.

View File

@ -3,7 +3,6 @@ from typing import Iterable
from eth2spec.phase0 import spec as spec_phase0 from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1 from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.phase_0.epoch_processing import ( from eth2spec.test.phase_0.epoch_processing import (
test_process_crosslinks,
test_process_final_updates, test_process_final_updates,
test_process_justification_and_finalization, test_process_justification_and_finalization,
test_process_registry_updates, test_process_registry_updates,
@ -35,8 +34,6 @@ def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typin
if __name__ == "__main__": if __name__ == "__main__":
gen_runner.run_generator("epoch_processing", [ gen_runner.run_generator("epoch_processing", [
create_provider('crosslinks', test_process_crosslinks, 'minimal'),
create_provider('crosslinks', test_process_crosslinks, 'mainnet'),
create_provider('final_updates', test_process_final_updates, 'minimal'), create_provider('final_updates', test_process_final_updates, 'minimal'),
create_provider('final_updates', test_process_final_updates, 'mainnet'), create_provider('final_updates', test_process_final_updates, 'mainnet'),
create_provider('justification_and_finalization', test_process_justification_and_finalization, 'minimal'), create_provider('justification_and_finalization', test_process_justification_and_finalization, 'minimal'),

View File

@ -1,5 +1,5 @@
from eth2spec.phase0 import spec as spec_phase0 from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1 # from eth2spec.phase1 import spec as spec_phase1
from eth2spec.utils import bls from eth2spec.utils import bls
from .helpers.genesis import create_genesis_state from .helpers.genesis import create_genesis_state
@ -137,7 +137,9 @@ def with_phases(phases):
if 'phase0' in run_phases: if 'phase0' in run_phases:
ret = run_with_spec_version(spec_phase0, *args, **kw) ret = run_with_spec_version(spec_phase0, *args, **kw)
if 'phase1' in run_phases: if 'phase1' in run_phases:
ret = run_with_spec_version(spec_phase1, *args, **kw) # temporarily disable phase 1 tests
return
# ret = run_with_spec_version(spec_phase1, *args, **kw)
return ret return ret
return wrapper return wrapper
return decorator return decorator

View File

@ -3,11 +3,10 @@ from typing import List
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.keys import privkeys from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils.bls import bls_sign, bls_aggregate_signatures from eth2spec.utils.bls import bls_sign, bls_aggregate_signatures
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
from eth2spec.utils.ssz.ssz_typing import Bitlist from eth2spec.utils.ssz.ssz_typing import Bitlist
def build_attestation_data(spec, state, slot, shard): def build_attestation_data(spec, state, slot, index):
assert state.slot >= slot assert state.slot >= slot
if slot == state.slot: if slot == state.slot:
@ -15,7 +14,7 @@ def build_attestation_data(spec, state, slot, shard):
else: else:
block_root = spec.get_block_root_at_slot(state, slot) block_root = spec.get_block_root_at_slot(state, slot)
current_epoch_start_slot = spec.compute_start_slot_of_epoch(spec.get_current_epoch(state)) current_epoch_start_slot = spec.compute_start_slot_at_epoch(spec.get_current_epoch(state))
if slot < current_epoch_start_slot: if slot < current_epoch_start_slot:
epoch_boundary_root = spec.get_block_root(state, spec.get_previous_epoch(state)) epoch_boundary_root = spec.get_block_root(state, spec.get_previous_epoch(state))
elif slot == current_epoch_start_slot: elif slot == current_epoch_start_slot:
@ -30,43 +29,30 @@ def build_attestation_data(spec, state, slot, shard):
source_epoch = state.current_justified_checkpoint.epoch source_epoch = state.current_justified_checkpoint.epoch
source_root = state.current_justified_checkpoint.root source_root = state.current_justified_checkpoint.root
if spec.compute_epoch_of_slot(slot) == spec.get_current_epoch(state):
parent_crosslink = state.current_crosslinks[shard]
else:
parent_crosslink = state.previous_crosslinks[shard]
return spec.AttestationData( return spec.AttestationData(
slot=slot,
index=index,
beacon_block_root=block_root, beacon_block_root=block_root,
source=spec.Checkpoint(epoch=source_epoch, root=source_root), source=spec.Checkpoint(epoch=source_epoch, root=source_root),
target=spec.Checkpoint(epoch=spec.compute_epoch_of_slot(slot), root=epoch_boundary_root), target=spec.Checkpoint(epoch=spec.compute_epoch_at_slot(slot), root=epoch_boundary_root),
crosslink=spec.Crosslink(
shard=shard,
start_epoch=parent_crosslink.end_epoch,
end_epoch=min(spec.compute_epoch_of_slot(slot), parent_crosslink.end_epoch + spec.MAX_EPOCHS_PER_CROSSLINK),
data_root=spec.Hash(),
parent_root=hash_tree_root(parent_crosslink),
),
) )
def get_valid_attestation(spec, state, slot=None, signed=False): def get_valid_attestation(spec, state, slot=None, index=None, signed=False):
if slot is None: if slot is None:
slot = state.slot slot = state.slot
if index is None:
index = 0
epoch = spec.compute_epoch_of_slot(slot) attestation_data = build_attestation_data(spec, state, slot, index)
epoch_start_shard = spec.get_start_shard(state, epoch)
committees_per_slot = spec.get_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT
attestation_data = build_attestation_data(spec, state, slot, shard) beacon_committee = spec.get_beacon_committee(
crosslink_committee = spec.get_crosslink_committee(
state, state,
attestation_data.target.epoch, attestation_data.slot,
attestation_data.crosslink.shard, attestation_data.index,
) )
committee_size = len(crosslink_committee) committee_size = len(beacon_committee)
aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size)) aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size))
custody_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size)) custody_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size))
attestation = spec.Attestation( attestation = spec.Attestation(
@ -129,12 +115,12 @@ def get_attestation_signature(spec, state, attestation_data, privkey, custody_bi
def fill_aggregate_attestation(spec, state, attestation): def fill_aggregate_attestation(spec, state, attestation):
crosslink_committee = spec.get_crosslink_committee( beacon_committee = spec.get_beacon_committee(
state, state,
attestation.data.target.epoch, attestation.data.slot,
attestation.data.crosslink.shard, attestation.data.index,
) )
for i in range(len(crosslink_committee)): for i in range(len(beacon_committee)):
attestation.aggregation_bits[i] = True attestation.aggregation_bits[i] = True

View File

@ -14,7 +14,7 @@ def sign_block(spec, state, block, proposer_index=None):
if block.slot == state.slot: if block.slot == state.slot:
proposer_index = spec.get_beacon_proposer_index(state) proposer_index = spec.get_beacon_proposer_index(state)
else: else:
if spec.compute_epoch_of_slot(state.slot) + 1 > spec.compute_epoch_of_slot(block.slot): if spec.compute_epoch_at_slot(state.slot) + 1 > spec.compute_epoch_at_slot(block.slot):
print("warning: block slot far away, and no proposer index manually given." print("warning: block slot far away, and no proposer index manually given."
" Signing block is slow due to transition for proposer index calculation.") " Signing block is slow due to transition for proposer index calculation.")
# use stub state to get proposer index of future slot # use stub state to get proposer index of future slot
@ -26,10 +26,10 @@ def sign_block(spec, state, block, proposer_index=None):
block.body.randao_reveal = bls_sign( block.body.randao_reveal = bls_sign(
privkey=privkey, privkey=privkey,
message_hash=hash_tree_root(spec.compute_epoch_of_slot(block.slot)), message_hash=hash_tree_root(spec.compute_epoch_at_slot(block.slot)),
domain=spec.get_domain( domain=spec.get_domain(
state, state,
message_epoch=spec.compute_epoch_of_slot(block.slot), message_epoch=spec.compute_epoch_at_slot(block.slot),
domain_type=spec.DOMAIN_RANDAO, domain_type=spec.DOMAIN_RANDAO,
) )
) )
@ -39,7 +39,7 @@ def sign_block(spec, state, block, proposer_index=None):
domain=spec.get_domain( domain=spec.get_domain(
state, state,
spec.DOMAIN_BEACON_PROPOSER, spec.DOMAIN_BEACON_PROPOSER,
spec.compute_epoch_of_slot(block.slot))) spec.compute_epoch_at_slot(block.slot)))
def apply_empty_block(spec, state): def apply_empty_block(spec, state):

View File

@ -80,13 +80,13 @@ def bitlist_from_int(max_len, num_bits, n):
def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False): def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False):
crosslink_committee = spec.get_crosslink_committee( beacon_committee = spec.get_beacon_committee(
state, state,
attestation.data.target.epoch, attestation.data.slot,
attestation.data.crosslink.shard, attestation.data.crosslink.shard,
) )
responder_index = crosslink_committee[0] responder_index = beacon_committee[0]
challenger_index = crosslink_committee[-1] challenger_index = beacon_committee[-1]
epoch = spec.get_randao_epoch_for_custody_period(attestation.data.target.epoch, epoch = spec.get_randao_epoch_for_custody_period(attestation.data.target.epoch,
responder_index) responder_index)

View File

@ -52,14 +52,18 @@ def next_epoch_with_attestations(spec,
block = build_empty_block_for_next_slot(spec, post_state) block = build_empty_block_for_next_slot(spec, post_state)
if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY: if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY:
slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
if slot_to_attest >= spec.compute_start_slot_of_epoch(spec.get_current_epoch(post_state)): committees_per_slot = spec.get_committee_count_at_slot(state, slot_to_attest)
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest) if slot_to_attest >= spec.compute_start_slot_at_epoch(spec.get_current_epoch(post_state)):
block.body.attestations.append(cur_attestation) for index in range(committees_per_slot):
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest, index=index)
block.body.attestations.append(cur_attestation)
if fill_prev_epoch: if fill_prev_epoch:
slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1
prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest) committees_per_slot = spec.get_committee_count_at_slot(state, slot_to_attest)
block.body.attestations.append(prev_attestation) for index in range(committees_per_slot):
prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest, index=index)
block.body.attestations.append(prev_attestation)
state_transition_and_sign_block(spec, post_state, block) state_transition_and_sign_block(spec, post_state, block)
blocks.append(block) blocks.append(block)

View File

@ -1,4 +1,9 @@
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases from eth2spec.test.context import (
spec_state_test,
expect_assertion_error,
always_bls, never_bls,
with_all_phases, with_phases,
)
from eth2spec.test.helpers.attestations import ( from eth2spec.test.helpers.attestations import (
get_valid_attestation, get_valid_attestation,
sign_aggregate_attestation, sign_aggregate_attestation,
@ -6,7 +11,6 @@ from eth2spec.test.helpers.attestations import (
) )
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
next_epoch, next_epoch,
next_slot,
) )
from eth2spec.test.helpers.block import apply_empty_block from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.utils.ssz.ssz_typing import Bitlist from eth2spec.utils.ssz.ssz_typing import Bitlist
@ -67,54 +71,6 @@ def test_success_previous_epoch(spec, state):
yield from run_attestation_processing(spec, state, attestation) yield from run_attestation_processing(spec, state, attestation)
@with_all_phases
@spec_state_test
def test_success_since_max_epochs_per_crosslink(spec, state):
# Do not run mainnet (64 epochs), that would mean the equivalent of ~7 hours chain simulation.
if spec.MAX_EPOCHS_PER_CROSSLINK > 4:
return
for _ in range(spec.MAX_EPOCHS_PER_CROSSLINK + 2):
next_epoch(spec, state)
apply_empty_block(spec, state)
attestation = get_valid_attestation(spec, state, signed=True)
data = attestation.data
# test logic sanity check: make sure the attestation only includes MAX_EPOCHS_PER_CROSSLINK epochs
assert data.crosslink.end_epoch - data.crosslink.start_epoch == spec.MAX_EPOCHS_PER_CROSSLINK
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(spec, state)
apply_empty_block(spec, state)
yield from run_attestation_processing(spec, state, attestation)
@with_all_phases
@spec_state_test
def test_wrong_end_epoch_with_max_epochs_per_crosslink(spec, state):
# Do not run mainnet (64 epochs), that would mean the equivalent of ~7 hours chain simulation.
if spec.MAX_EPOCHS_PER_CROSSLINK > 4:
return
for _ in range(spec.MAX_EPOCHS_PER_CROSSLINK + 2):
next_epoch(spec, state)
apply_empty_block(spec, state)
attestation = get_valid_attestation(spec, state)
data = attestation.data
# test logic sanity check: make sure the attestation only includes MAX_EPOCHS_PER_CROSSLINK epochs
assert data.crosslink.end_epoch - data.crosslink.start_epoch == spec.MAX_EPOCHS_PER_CROSSLINK
# Now change it to be different
data.crosslink.end_epoch += 1
sign_attestation(spec, state, attestation)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(spec, state)
apply_empty_block(spec, state)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
@always_bls @always_bls
@ -168,27 +124,41 @@ def test_old_source_epoch(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_wrong_shard(spec, state): @always_bls
def test_wrong_index_for_committee_signature(spec, state):
attestation = get_valid_attestation(spec, state) attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.crosslink.shard += 1 attestation.data.index += 1
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False) yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_invalid_shard(spec, state): @never_bls
def test_wrong_index_for_slot(spec, state):
committees_per_slot = spec.get_committee_count_at_slot(state, state.slot)
assert committees_per_slot < spec.MAX_COMMITTEES_PER_SLOT
index = committees_per_slot
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.index = index
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
@never_bls
def test_invalid_index(spec, state):
attestation = get_valid_attestation(spec, state) attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
# off by one (with respect to valid range) on purpose # off by one (with respect to valid range) on purpose
attestation.data.crosslink.shard = spec.SHARD_COUNT attestation.data.index = spec.MAX_COMMITTEES_PER_SLOT
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False) yield from run_attestation_processing(spec, state, attestation, False)
@ -290,73 +260,6 @@ def test_bad_source_root(spec, state):
yield from run_attestation_processing(spec, state, attestation, False) yield from run_attestation_processing(spec, state, attestation, False)
@with_phases(['phase0'])
@spec_state_test
def test_non_zero_crosslink_data_root(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.crosslink.data_root = b'\x42' * 32
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_bad_parent_crosslink(spec, state):
state.slot = spec.SLOTS_PER_EPOCH - 1
next_epoch(spec, state)
apply_empty_block(spec, state)
attestation = get_valid_attestation(spec, state, signed=False)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(spec, state)
apply_empty_block(spec, state)
attestation.data.crosslink.parent_root = b'\x27' * 32
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_bad_crosslink_start_epoch(spec, state):
state.slot = spec.SLOTS_PER_EPOCH - 1
next_epoch(spec, state)
apply_empty_block(spec, state)
attestation = get_valid_attestation(spec, state, signed=False)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(spec, state)
apply_empty_block(spec, state)
attestation.data.crosslink.start_epoch += 1
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_bad_crosslink_end_epoch(spec, state):
state.slot = spec.SLOTS_PER_EPOCH - 1
next_epoch(spec, state)
apply_empty_block(spec, state)
attestation = get_valid_attestation(spec, state, signed=False)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(spec, state)
apply_empty_block(spec, state)
attestation.data.crosslink.end_epoch += 1
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_inconsistent_bits(spec, state): def test_inconsistent_bits(spec, state):

View File

@ -1,7 +1,6 @@
process_calls = [ process_calls = [
'process_justification_and_finalization', 'process_justification_and_finalization',
'process_crosslinks',
'process_rewards_and_penalties', 'process_rewards_and_penalties',
'process_registry_updates', 'process_registry_updates',
'process_reveal_deadlines', 'process_reveal_deadlines',

View File

@ -1,132 +0,0 @@
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
)
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.attestations import (
add_attestation_to_state,
fill_aggregate_attestation,
get_valid_attestation,
sign_attestation,
)
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with
def run_process_crosslinks(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_crosslinks')
@with_all_phases
@spec_state_test
def test_no_attestations(spec, state):
yield from run_process_crosslinks(spec, state)
for shard in range(spec.SHARD_COUNT):
assert state.previous_crosslinks[shard] == state.current_crosslinks[shard]
@with_all_phases
@spec_state_test
def test_single_crosslink_update_from_current_epoch(spec, state):
next_epoch(spec, state)
attestation = get_valid_attestation(spec, state, signed=True)
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
shard = attestation.data.crosslink.shard
pre_crosslink = deepcopy(state.current_crosslinks[shard])
yield from run_process_crosslinks(spec, state)
assert state.previous_crosslinks[shard] != state.current_crosslinks[shard]
assert pre_crosslink != state.current_crosslinks[shard]
@with_all_phases
@spec_state_test
def test_single_crosslink_update_from_previous_epoch(spec, state):
next_epoch(spec, state)
attestation = get_valid_attestation(spec, state, signed=True)
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
shard = attestation.data.crosslink.shard
pre_crosslink = deepcopy(state.current_crosslinks[shard])
crosslink_deltas = spec.get_crosslink_deltas(state)
yield from run_process_crosslinks(spec, state)
assert state.previous_crosslinks[shard] != state.current_crosslinks[shard]
assert pre_crosslink != state.current_crosslinks[shard]
# ensure rewarded
for index in spec.get_crosslink_committee(
state,
attestation.data.target.epoch,
attestation.data.crosslink.shard):
assert crosslink_deltas[0][index] > 0
assert crosslink_deltas[1][index] == 0
@with_all_phases
@spec_state_test
def test_double_late_crosslink(spec, state):
if spec.get_committee_count(state, spec.get_current_epoch(state)) < spec.SHARD_COUNT:
print("warning: ignoring test, test-assumptions are incompatible with configuration")
return
next_epoch(spec, state)
state.slot += 4
attestation_1 = get_valid_attestation(spec, state, signed=True)
fill_aggregate_attestation(spec, state, attestation_1)
# add attestation_1 to next epoch
next_epoch(spec, state)
add_attestation_to_state(spec, state, attestation_1, state.slot + 1)
for _ in range(spec.SLOTS_PER_EPOCH):
attestation_2 = get_valid_attestation(spec, state)
if attestation_2.data.crosslink.shard == attestation_1.data.crosslink.shard:
sign_attestation(spec, state, attestation_2)
break
next_slot(spec, state)
apply_empty_block(spec, state)
fill_aggregate_attestation(spec, state, attestation_2)
# add attestation_2 in the next epoch after attestation_1 has
# already updated the relevant crosslink
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
crosslink_deltas = spec.get_crosslink_deltas(state)
yield from run_process_crosslinks(spec, state)
shard = attestation_2.data.crosslink.shard
# ensure that the current crosslinks were not updated by the second attestation
assert state.previous_crosslinks[shard] == state.current_crosslinks[shard]
# ensure no reward, only penalties for the failed crosslink
for index in spec.get_crosslink_committee(
state,
attestation_2.data.target.epoch,
attestation_2.data.crosslink.shard):
assert crosslink_deltas[0][index] == 0
assert crosslink_deltas[1][index] > 0

View File

@ -8,14 +8,6 @@ def run_process_just_and_fin(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_justification_and_finalization') yield from run_epoch_processing_with(spec, state, 'process_justification_and_finalization')
def get_shards_for_slot(spec, state, slot):
epoch = spec.compute_epoch_of_slot(slot)
epoch_start_shard = spec.get_start_shard(state, epoch)
committees_per_slot = spec.get_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT
return [shard + i for i in range(committees_per_slot)]
def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False): def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False):
# we must be at the end of the epoch # we must be at the end of the epoch
assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0
@ -33,15 +25,16 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
total_balance = spec.get_total_active_balance(state) total_balance = spec.get_total_active_balance(state)
remaining_balance = total_balance * 2 // 3 remaining_balance = total_balance * 2 // 3
start_slot = spec.compute_start_slot_of_epoch(epoch) start_slot = spec.compute_start_slot_at_epoch(epoch)
for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH): for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH):
for shard in get_shards_for_slot(spec, state, slot): committees_per_slot = spec.get_committee_count_at_slot(state, slot)
for index in range(committees_per_slot):
# Check if we already have had sufficient balance. (and undone if we don't want it). # Check if we already have had sufficient balance. (and undone if we don't want it).
# If so, do not create more attestations. (we do not have empty pending attestations normally anyway) # If so, do not create more attestations. (we do not have empty pending attestations normally anyway)
if remaining_balance < 0: if remaining_balance < 0:
return return
committee = spec.get_crosslink_committee(state, spec.compute_epoch_of_slot(slot), shard) committee = spec.get_beacon_committee(state, slot, index)
# Create a bitfield filled with the given count per attestation, # Create a bitfield filled with the given count per attestation,
# exactly on the right-most part of the committee field. # exactly on the right-most part of the committee field.
@ -60,10 +53,11 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
attestations.append(spec.PendingAttestation( attestations.append(spec.PendingAttestation(
aggregation_bits=aggregation_bits, aggregation_bits=aggregation_bits,
data=spec.AttestationData( data=spec.AttestationData(
slot=slot,
beacon_block_root=b'\xff' * 32, # irrelevant to testing beacon_block_root=b'\xff' * 32, # irrelevant to testing
source=source, source=source,
target=target, target=target,
crosslink=spec.Crosslink(shard=shard) index=index,
), ),
inclusion_delay=1, inclusion_delay=1,
)) ))
@ -80,7 +74,7 @@ def get_checkpoints(spec, epoch):
def put_checkpoints_in_block_roots(spec, state, checkpoints): def put_checkpoints_in_block_roots(spec, state, checkpoints):
for c in checkpoints: for c in checkpoints:
state.block_roots[spec.compute_start_slot_of_epoch(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root state.block_roots[spec.compute_start_slot_at_epoch(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root
def finalize_on_234(spec, state, epoch, sufficient_support): def finalize_on_234(spec, state, epoch, sufficient_support):