diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 838d9d681..b57aa7ff4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -84,7 +84,6 @@ - [`get_committee_count`](#get_committee_count) - [`get_crosslink_committee`](#get_crosslink_committee) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - - [`get_attestation_data_slot`](#get_attestation_data_slot) - [`get_total_balance`](#get_total_balance) - [`get_total_active_balance`](#get_total_active_balance) - [`get_domain`](#get_domain) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 69962b6fe..9bd9c70ee 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -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 @@ -101,6 +102,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 + shard: Shard +``` + ### `ShardBlock` ```python diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index 23d1a8f8f..00c25b340 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -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.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: @@ -30,40 +29,27 @@ 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( state, attestation_data.target.epoch, - attestation_data.crosslink.shard, + attestation_data.index, ) committee_size = len(crosslink_committee) @@ -132,7 +118,7 @@ def fill_aggregate_attestation(spec, state, attestation): crosslink_committee = spec.get_crosslink_committee( state, attestation.data.target.epoch, - attestation.data.crosslink.shard, + attestation.data.index, ) for i in range(len(crosslink_committee)): attestation.aggregation_bits[i] = True diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index 8ae45788f..b3952b7ea 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -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 ( get_valid_attestation, sign_aggregate_attestation, @@ -6,7 +11,6 @@ from eth2spec.test.helpers.attestations import ( ) from eth2spec.test.helpers.state import ( next_epoch, - next_slot, ) from eth2spec.test.helpers.block import apply_empty_block 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) -@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 @spec_state_test @always_bls @@ -168,27 +124,13 @@ def test_old_source_epoch(spec, state): @with_all_phases @spec_state_test -def test_wrong_shard(spec, state): - attestation = get_valid_attestation(spec, state) - state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY - - attestation.data.crosslink.shard += 1 - - sign_attestation(spec, state, attestation) - - yield from run_attestation_processing(spec, state, attestation, False) - - -@with_all_phases -@spec_state_test -def test_invalid_shard(spec, state): +@never_bls +def test_invalid_index(spec, state): attestation = get_valid_attestation(spec, state) state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY # off by one (with respect to valid range) on purpose - attestation.data.crosslink.shard = spec.SHARD_COUNT - - sign_attestation(spec, state, attestation) + attestation.data.index = spec.COMMITTEES_PER_SLOT yield from run_attestation_processing(spec, state, attestation, False) @@ -290,73 +232,6 @@ def test_bad_source_root(spec, state): 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 @spec_state_test def test_inconsistent_bits(spec, state): diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py deleted file mode 100644 index 41d784c50..000000000 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ /dev/null @@ -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