initial removal and cleanup of shard/crosslink from phase 0

This commit is contained in:
Danny Ryan 2019-10-12 11:48:34 +09:00
parent fffdb24708
commit dfdf3ab5cf
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
3 changed files with 30 additions and 157 deletions

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)
@ -84,8 +83,6 @@
- [`get_seed`](#get_seed) - [`get_seed`](#get_seed)
- [`get_committee_count`](#get_committee_count) - [`get_committee_count`](#get_committee_count)
- [`get_crosslink_committee`](#get_crosslink_committee) - [`get_crosslink_committee`](#get_crosslink_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_attestation_data_slot`](#get_attestation_data_slot)
- [`get_total_balance`](#get_total_balance) - [`get_total_balance`](#get_total_balance)
@ -105,7 +102,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)
@ -174,6 +170,7 @@ The following values are (non-configurable) constants used throughout the specif
| Name | Value | | Name | Value |
| - | - | | - | - |
| `COMMITTEES_PER_SLOT` | `2**5` (= 32) |
| `SHARD_COUNT` | `2**10` (= 1,024) | | `SHARD_COUNT` | `2**10` (= 1,024) |
| `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**12` (= 4,096) |
@ -305,29 +302,18 @@ 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
# 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 # Index -- Maybe remove
crosslink: Crosslink index: uint64
``` ```
#### `AttestationDataAndCustodyBit` #### `AttestationDataAndCustodyBit`
@ -507,16 +493,12 @@ class BeaconState(Container):
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 # Shuffling
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
@ -885,54 +867,32 @@ def get_committee_count(state: BeaconState, epoch: Epoch) -> uint64:
""" """
Return the number of committees at ``epoch``. Return the number of committees at ``epoch``.
""" """
# Consider not hard coding but just return committees per slot for now
"""
committees_per_slot = max(1, min( committees_per_slot = max(1, min(
SHARD_COUNT // SLOTS_PER_EPOCH, SHARD_COUNT // SLOTS_PER_EPOCH,
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 return committees_per_slot * SLOTS_PER_EPOCH
"""
return COMMITTEES_PER_SLOT
``` ```
#### `get_crosslink_committee` #### `get_crosslink_committee`
```python ```python
def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> Sequence[ValidatorIndex]: def get_crosslink_committee(state: BeaconState, epoch: Epoch, index: uint64) -> Sequence[ValidatorIndex]:
""" """
Return the crosslink committee at ``epoch`` for ``shard``. Return the crosslink committee at ``epoch`` for ``index``.
""" """
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=index,
count=get_committee_count(state, epoch), count=get_committee_count(state, 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 +906,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 +967,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_crosslink_committee(state, data.target.epoch, 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 +1147,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 +1177,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 +1195,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 +1238,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
@ -1384,36 +1300,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) rewards1, penalties1 = 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), rewards1[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index]) decrease_balance(state, ValidatorIndex(index), penalties1[index])
``` ```
#### Registry updates #### Registry updates
@ -1481,8 +1376,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 = []
@ -1609,37 +1502,28 @@ 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 < COMMITTEES_PER_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))
attestation_slot = get_attestation_data_slot(state, data) assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
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) committee = get_crosslink_committee(state, data.target.epoch, data.index)
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

@ -192,7 +192,7 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
# 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) attestation_slot = attestation.data.slot
assert store.time >= (attestation_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

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)
@ -135,28 +134,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], uint64, 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_of_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(COMMITTEES_PER_SLOT):
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT committee = get_crosslink_committee(state, epoch, 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, index, Slot(slot)
return None return None
``` ```
@ -176,7 +172,7 @@ def is_proposer(state: BeaconState,
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.
@ -278,7 +274,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`.
@ -303,16 +299,9 @@ Set `attestation_data.beacon_block_root = signing_root(head_block)`.
- Let `start_slot = compute_start_slot_of_epoch(get_current_epoch(head_state))`. - Let `start_slot = compute_start_slot_of_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 ##### Index
Construct `attestation_data.crosslink` via the following. Set `attestation_data.index = index` where `index` is the index associated with the validator's committee.
- 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