Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Shards/Crosslinks from Phase 0 #1428

Merged
merged 24 commits into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions configs/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

# Misc
# ---------------------------------------------------------------
# 2**10 (= 1,024)
SHARD_COUNT: 1024
# 2**5 (= 32)
MAX_COMMITTEES_PER_SLOT: 32
# 2**7 (= 128)
TARGET_COMMITTEE_SIZE: 128
# 2**12 (= 4,096)
Expand Down
4 changes: 2 additions & 2 deletions configs/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# Misc
# ---------------------------------------------------------------

# [customized] Just 8 shards for testing purposes
SHARD_COUNT: 8
# [customized] Just 2 committees for slot for testing purposes
MAX_COMMITTEES_PER_SLOT: 4
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
# [customized] unsecure, but fast
TARGET_COMMITTEE_SIZE: 4
# 2**12 (= 4,096)
Expand Down
184 changes: 32 additions & 152 deletions specs/core/0_beacon-chain.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion specs/core/0_fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
assert store.time >= (attestation_slot + 1) * SECONDS_PER_SLOT
djrtwo marked this conversation as resolved.
Show resolved Hide resolved

# Get state at the `target` to validate attestation and calculate the committees
Expand Down
1 change: 1 addition & 0 deletions specs/core/1_beacon-chain-misc.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

| Name | Value | Unit | Duration
| - | - | - | - |
| `MAX_EPOCHS_PER_CROSSLINK` | `2**6` (= 64) | epochs | ~7 hours |
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
| `MAX_SHARD_RECEIPT_PROOFS` | `2**0` (= 1) | - | - |
| `PERIOD_COMMITTEE_ROOT_LENGTH` | `2**8` (= 256) | periods | ~9 months |
| `MINOR_REWARD_QUOTIENT` | `2**8` (=256) | - | - |
Expand Down
3 changes: 2 additions & 1 deletion specs/core/1_custody-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| - | - |
| `BLS12_381_Q` | `4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787` |
| `MINOR_REWARD_QUOTIENT` | `2**8` (= 256) |
| `MAX_EPOCHS_PER_CROSSLINK` | `2**6` (= 64) | epochs | ~7 hours |

### Custody game parameters

Expand Down Expand Up @@ -623,7 +624,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) ->
chunk_count = get_custody_chunk_count(attestation.data.crosslink)
assert chunk_count == len(challenge.chunk_bits)
# 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)]
assert custody_bit != get_chunk_bits_root(challenge.chunk_bits)
# Add new bit challenge record
Expand Down
10 changes: 10 additions & 0 deletions specs/core/1_shard-data-chains.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ This document describes the shard transition function (data layer only) and the

| Name | SSZ equivalent | Description |
| - | - | - |
| `Shard` | `uint64` | a shard number |
| `ShardSlot` | `uint64` | a shard slot number |

## Configuration
Expand All @@ -61,6 +62,7 @@ This document describes the shard transition function (data layer only) and the

| Name | Value |
| - | - |
| `SHARD_COUNT` | `2**10` (= 1,024) |
| `MIN_BLOCK_BODY_PRICE` | `2**0` (= 1) |
| `MAX_PERIOD_COMMITTEE_SIZE` | `2**7` (= 128) |
| `SHARD_HEADER_SIZE` | `2**10` (= 1024) |
Expand Down Expand Up @@ -101,6 +103,14 @@ This document describes the shard transition function (data layer only) and the

## Containers

### `Crosslink`

```python
class Crosslink(Container):
# STUB: placeholder data structure while reworking phase 0
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
shard: Shard
```

### `ShardBlock`

```python
Expand Down
1 change: 0 additions & 1 deletion specs/test_formats/epoch_processing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ The provided pre-state is already transitioned to just before the specific sub-t
Sub-transitions:

- `justification_and_finalization`
- `crosslinks`
- *`rewards_and_penalties` - planned testing extension*
- `registry_updates`
- `slashings`
Expand Down
33 changes: 11 additions & 22 deletions specs/validator/0_beacon-chain-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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], CommitteeIndex, 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(get_committees_per_slot(state, Slot(slot))):
committee = get_beacon_committee(state, Slot(slot), CommitteeIndex(index))
if validator_index in committee:
return committee, shard, Slot(slot)
return committee, CommitteeIndex(index), Slot(slot)
return None
```

Expand All @@ -170,13 +166,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*: `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

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.

Expand Down Expand Up @@ -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`.

djrtwo marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -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

Expand Down
3 changes: 0 additions & 3 deletions test_generators/epoch_processing/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.phase_0.epoch_processing import (
test_process_crosslinks,
test_process_final_updates,
test_process_justification_and_finalization,
test_process_registry_updates,
Expand Down Expand Up @@ -35,8 +34,6 @@ def cases_fn() -> Iterable[gen_typing.TestCase]:

if __name__ == "__main__":
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, 'mainnet'),
create_provider('justification_and_finalization', test_process_justification_and_finalization, 'minimal'),
Expand Down
6 changes: 4 additions & 2 deletions test_libs/pyspec/eth2spec/test/context.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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 .helpers.genesis import create_genesis_state
Expand Down Expand Up @@ -137,7 +137,9 @@ def wrapper(*args, **kw):
if 'phase0' in run_phases:
ret = run_with_spec_version(spec_phase0, *args, **kw)
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 wrapper
return decorator
44 changes: 15 additions & 29 deletions test_libs/pyspec/eth2spec/test/helpers/attestations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.keys import privkeys
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


def build_attestation_data(spec, state, slot, shard):
def build_attestation_data(spec, state, slot, index):
assert state.slot >= slot

if slot == state.slot:
Expand All @@ -30,43 +29,30 @@ def build_attestation_data(spec, state, slot, shard):
source_epoch = state.current_justified_checkpoint.epoch
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(
slot=slot,
beacon_block_root=block_root,
source=spec.Checkpoint(epoch=source_epoch, root=source_root),
target=spec.Checkpoint(epoch=spec.compute_epoch_of_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),
),
index=index,
)


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:
slot = state.slot
if index is None:
index = 0

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

attestation_data = build_attestation_data(spec, state, slot, shard)
attestation_data = build_attestation_data(spec, state, slot, index)

crosslink_committee = spec.get_crosslink_committee(
beacon_committee = spec.get_beacon_committee(
state,
attestation_data.target.epoch,
attestation_data.crosslink.shard,
attestation_data.slot,
attestation_data.index,
)

committee_size = len(crosslink_committee)
committee_size = len(beacon_committee)
aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size))
custody_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size))
attestation = spec.Attestation(
Expand Down Expand Up @@ -129,12 +115,12 @@ def get_attestation_signature(spec, state, attestation_data, privkey, custody_bi


def fill_aggregate_attestation(spec, state, attestation):
crosslink_committee = spec.get_crosslink_committee(
beacon_committee = spec.get_beacon_committee(
state,
attestation.data.target.epoch,
attestation.data.crosslink.shard,
attestation.data.slot,
attestation.data.index,
)
for i in range(len(crosslink_committee)):
for i in range(len(beacon_committee)):
attestation.aggregation_bits[i] = True


Expand Down
8 changes: 4 additions & 4 deletions test_libs/pyspec/eth2spec/test/helpers/custody.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
crosslink_committee = spec.get_crosslink_committee(
beacon_committee = spec.get_beacon_committee(
state,
attestation.data.target.epoch,
attestation.data.slot,
attestation.data.crosslink.shard,
)
responder_index = crosslink_committee[0]
challenger_index = crosslink_committee[-1]
responder_index = beacon_committee[0]
challenger_index = beacon_committee[-1]

epoch = spec.get_randao_epoch_for_custody_period(attestation.data.target.epoch,
responder_index)
Expand Down
12 changes: 8 additions & 4 deletions test_libs/pyspec/eth2spec/test/helpers/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,18 @@ def next_epoch_with_attestations(spec,
block = build_empty_block_for_next_slot(spec, post_state)
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
committees_per_slot = spec.get_committees_per_slot(state, slot_to_attest)
if slot_to_attest >= spec.compute_start_slot_of_epoch(spec.get_current_epoch(post_state)):
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest)
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:
slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1
prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest)
block.body.attestations.append(prev_attestation)
committees_per_slot = spec.get_committees_per_slot(state, slot_to_attest)
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)
blocks.append(block)
Expand Down
Loading