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)
- [`Checkpoint`](#checkpoint)
- [`Validator`](#validator)
- [`Crosslink`](#crosslink)
- [`AttestationData`](#attestationdata)
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
- [`IndexedAttestation`](#indexedattestation)
@ -84,8 +83,6 @@
- [`get_seed`](#get_seed)
- [`get_committee_count`](#get_committee_count)
- [`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_attestation_data_slot`](#get_attestation_data_slot)
- [`get_total_balance`](#get_total_balance)
@ -105,7 +102,6 @@
- [Epoch processing](#epoch-processing)
- [Helper functions](#helper-functions-1)
- [Justification and finalization](#justification-and-finalization)
- [Crosslinks](#crosslinks)
- [Rewards and penalties](#rewards-and-penalties-1)
- [Registry updates](#registry-updates)
- [Slashings](#slashings)
@ -174,6 +170,7 @@ The following values are (non-configurable) constants used throughout the specif
| Name | Value |
| - | - |
| `COMMITTEES_PER_SLOT` | `2**5` (= 32) |
| `SHARD_COUNT` | `2**10` (= 1,024) |
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
| `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
```
#### `Crosslink`
```python
class Crosslink(Container):
shard: Shard
parent_root: Hash
# Crosslinking data
start_epoch: Epoch
end_epoch: Epoch
data_root: Hash
```
#### `AttestationData`
```python
class AttestationData(Container):
slot: Slot
# LMD GHOST vote
beacon_block_root: Hash
# FFG vote
source: Checkpoint
target: Checkpoint
# Crosslink vote
crosslink: Crosslink
# Index -- Maybe remove
index: uint64
```
#### `AttestationDataAndCustodyBit`
@ -507,16 +493,12 @@ class BeaconState(Container):
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
# Shuffling
start_shard: Shard
randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR]
# Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
# Attestations
previous_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
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
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``.
"""
# Consider not hard coding but just return committees per slot for now
"""
committees_per_slot = max(1, min(
SHARD_COUNT // SLOTS_PER_EPOCH,
len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE,
))
return committees_per_slot * SLOTS_PER_EPOCH
"""
return COMMITTEES_PER_SLOT
```
#### `get_crosslink_committee`
```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(
indices=get_active_validator_indices(state, epoch),
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),
)
```
#### `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`
```python
@ -946,18 +906,6 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
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`
```python
@ -1019,7 +967,7 @@ def get_attesting_indices(state: BeaconState,
"""
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])
```
@ -1199,7 +1147,6 @@ def process_slot(state: BeaconState) -> None:
```python
def process_epoch(state: BeaconState) -> None:
process_justification_and_finalization(state)
process_crosslinks(state)
process_rewards_and_penalties(state)
process_registry_updates(state)
# @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]:
return [
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))
```
```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
```python
@ -1308,20 +1238,6 @@ def process_justification_and_finalization(state: BeaconState) -> None:
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
```python
@ -1384,36 +1300,15 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence
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
def process_rewards_and_penalties(state: BeaconState) -> None:
if get_current_epoch(state) == GENESIS_EPOCH:
return
rewards1, penalties1 = get_attestation_deltas(state)
rewards2, penalties2 = get_crosslink_deltas(state)
for index in range(len(state.validators)):
increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index])
increase_balance(state, ValidatorIndex(index), rewards1[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index])
```
#### Registry updates
@ -1481,8 +1376,6 @@ def process_final_updates(state: BeaconState) -> None:
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
historical_batch = HistoricalBatch(block_roots=state.block_roots, state_roots=state.state_roots)
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
state.previous_epoch_attestations = state.current_epoch_attestations
state.current_epoch_attestations = []
@ -1609,37 +1502,28 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla
```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
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))
attestation_slot = get_attestation_data_slot(state, data)
assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.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)
pending_attestation = PendingAttestation(
data=data,
aggregation_bits=attestation.aggregation_bits,
inclusion_delay=state.slot - attestation_slot,
inclusion_delay=state.slot - data.slot,
proposer_index=get_beacon_proposer_index(state),
)
if data.target.epoch == get_current_epoch(state):
assert data.source == state.current_justified_checkpoint
parent_crosslink = state.current_crosslinks[data.crosslink.shard]
state.current_epoch_attestations.append(pending_attestation)
else:
assert data.source == state.previous_justified_checkpoint
parent_crosslink = state.previous_crosslinks[data.crosslink.shard]
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
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.
# 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
# Get state at the `target` to validate attestation and calculate the committees

View File

@ -41,7 +41,6 @@
- [Attestation data](#attestation-data)
- [LMD GHOST vote](#lmd-ghost-vote)
- [FFG vote](#ffg-vote)
- [Crosslink vote](#crosslink-vote)
- [Construct attestation](#construct-attestation)
- [Data](#data)
- [Aggregation bits](#aggregation-bits)
@ -135,28 +134,25 @@ A validator can get committee assignments for a given epoch using the following
```python
def get_committee_assignment(state: BeaconState,
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``.
``assignment`` returned is a tuple of the following form:
* ``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
Return None if no assignment.
"""
next_epoch = get_current_epoch(state) + 1
assert epoch <= next_epoch
committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH
start_slot = compute_start_slot_of_epoch(epoch)
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT
for i in range(committees_per_slot):
shard = Shard((slot_start_shard + i) % SHARD_COUNT)
committee = get_crosslink_committee(state, epoch, shard)
for index in range(COMMITTEES_PER_SLOT):
committee = get_crosslink_committee(state, epoch, index)
if validator_index in committee:
return committee, shard, Slot(slot)
return committee, index, Slot(slot)
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.
`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.
@ -278,7 +274,7 @@ Up to `MAX_VOLUNTARY_EXITS`, [`VoluntaryExit`](../core/0_beacon-chain.md#volunta
### 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`.
@ -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 `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.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.
Set `attestation_data.index = index` where `index` is the index associated with the validator's committee.
#### Construct attestation