From d8431f847648041dd3efd4d55abc92ce2a872f44 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sun, 13 Oct 2019 13:53:43 +0900 Subject: [PATCH] add start index back in --- configs/mainnet.yaml | 2 +- configs/minimal.yaml | 2 +- specs/core/0_beacon-chain.md | 72 +++++++++++++++++-- specs/validator/0_beacon-chain-validator.md | 4 +- .../eth2spec/test/helpers/attestations.py | 5 +- .../pyspec/eth2spec/test/helpers/state.py | 10 ++- .../test_process_attestation.py | 8 ++- ..._process_justification_and_finalization.py | 5 +- 8 files changed, 96 insertions(+), 12 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index a45e965d2..1210d8076 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -6,7 +6,7 @@ # Misc # --------------------------------------------------------------- # 2**5 (= 32) -COMMITTEES_PER_SLOT: 32 +MAX_COMMITTEES_PER_SLOT: 32 # 2**7 (= 128) TARGET_COMMITTEE_SIZE: 128 # 2**12 (= 4,096) diff --git a/configs/minimal.yaml b/configs/minimal.yaml index dfed19426..a6040b3a3 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -5,7 +5,7 @@ # --------------------------------------------------------------- # [customized] Just 2 committees for slot for testing purposes -COMMITTEES_PER_SLOT: 2 +MAX_COMMITTEES_PER_SLOT: 2 # [customized] unsecure, but fast TARGET_COMMITTEE_SIZE: 4 # 2**12 (= 4,096) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2ceae488e..7b6b876de 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -168,8 +168,8 @@ 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) | +| `MAX_COMMITTEES_PER_SLOT` | `2**5` (= 32) | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | | `MAX_VALIDATORS_PER_COMMITTEE` | `2**12` (= 4,096) | | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | @@ -490,6 +490,7 @@ class BeaconState(Container): validators: List[Validator, VALIDATOR_REGISTRY_LIMIT] balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT] # Shuffling + start_index: uint64 randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Slashings slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances @@ -857,6 +858,21 @@ def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Hash: return hash(domain_type + int_to_bytes(epoch, length=8) + mix) ``` + +#### `get_committee_count` + +```python +def get_committee_count(state: BeaconState, epoch: Epoch) -> uint64: + """ + Return the number of committees at ``epoch``. + """ + committees_per_slot = max(1, min( + MAX_COMMITTEES_PER_SLOT, + len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, + )) + return committees_per_slot * SLOTS_PER_EPOCH +``` + #### `get_crosslink_committee` ```python @@ -865,14 +881,60 @@ def get_crosslink_committee(state: BeaconState, slot: Slot, index: uint64) -> Se Return the crosslink committee at ``epoch`` for ``index``. """ epoch = compute_epoch_of_slot(slot) + committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH + slot_start_index = get_slot_start_index(state, slot) + slot_offset = (index + MAX_COMMITTEES_PER_SLOT - slot_start_index) % MAX_COMMITTEES_PER_SLOT + epoch_offset = slot_offset + (slot % SLOTS_PER_EPOCH) * committees_per_slot + print(epoch_offset) + return compute_committee( indices=get_active_validator_indices(state, epoch), seed=get_seed(state, epoch, DOMAIN_BEACON_ATTESTER), - index=(slot % SLOTS_PER_EPOCH) * COMMITTEES_PER_SLOT + index, - count=COMMITTEES_PER_SLOT * SLOTS_PER_EPOCH, + index=epoch_offset, + count=get_committee_count(state, epoch), ) ``` +#### `get_slot_start_index` + +```python +def get_slot_start_index(state: BeaconState, slot: Slot) -> uint64: + """ + Return the start index of the 0th committee at ``slot``. + """ + epoch = compute_epoch_of_slot(slot) + committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH + slot_start_index = ((slot % SLOTS_PER_EPOCH) * committees_per_slot + get_start_index(state, epoch)) % MAX_COMMITTEES_PER_SLOT + return slot_start_index +``` + +#### `get_start_index` + +```python +def get_start_index(state: BeaconState, epoch: Epoch) -> uint64: + """ + Return the start index of the 0th committee at ``epoch``. + """ + assert epoch <= get_current_epoch(state) + 1 + check_epoch = Epoch(get_current_epoch(state) + 1) + index = (state.start_index + get_index_delta(state, get_current_epoch(state))) % MAX_COMMITTEES_PER_SLOT + MAX_COMMITTEES_PER_EPOCH = MAX_COMMITTEES_PER_SLOT * SLOTS_PER_EPOCH + while check_epoch > epoch: + check_epoch -= Epoch(1) + index = (index + MAX_COMMITTEES_PER_EPOCH - get_index_delta(state, check_epoch)) % MAX_COMMITTEES_PER_SLOT + return index +``` + +#### `get_index_delta` + +```python +def get_index_delta(state: BeaconState, epoch: Epoch) -> uint64: + """ + Return the amount to increase ``state.start_index`` at ``epoch``. + """ + return get_committee_count(state, epoch) +``` + #### `get_beacon_proposer_index` ```python @@ -1356,6 +1418,8 @@ 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_index = (state.start_index + get_index_delta(state, current_epoch)) % MAX_COMMITTEES_PER_SLOT # Rotate current/previous epoch attestations state.previous_epoch_attestations = state.current_epoch_attestations state.current_epoch_attestations = [] @@ -1482,7 +1546,7 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla ```python def process_attestation(state: BeaconState, attestation: Attestation) -> None: data = attestation.data - assert data.index < COMMITTEES_PER_SLOT + assert data.index < MAX_COMMITTEES_PER_SLOT 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 diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 1efdadb35..774837ced 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -149,7 +149,9 @@ def get_committee_assignment(state: BeaconState, start_slot = compute_start_slot_of_epoch(epoch) for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH): - for index in range(COMMITTEES_PER_SLOT): + slot_start_index = get_slot_start_index(state, Slot(slot)) + for i in range(get_committee_count(state, epoch) // SLOTS_PER_EPOCH): + index = (slot_start_index + i) % MAX_COMMITTEES_PER_SLOT committee = get_crosslink_committee(state, Slot(slot), index) if validator_index in committee: return committee, index, Slot(slot) diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index afd51b0bd..49d6b6ad7 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -42,7 +42,10 @@ 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 + index = spec.get_slot_start_index(state, slot) + print(slot) + print(index) + print(spec.get_committee_count(state, spec.compute_epoch_of_slot(slot))) attestation_data = build_attestation_data(spec, state, slot, index) diff --git a/test_libs/pyspec/eth2spec/test/helpers/state.py b/test_libs/pyspec/eth2spec/test/helpers/state.py index 5a2f72ff3..6ae845f69 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/state.py +++ b/test_libs/pyspec/eth2spec/test/helpers/state.py @@ -51,15 +51,21 @@ def next_epoch_with_attestations(spec, for _ in range(spec.SLOTS_PER_EPOCH): block = build_empty_block_for_next_slot(spec, post_state) if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY: + committees_per_slot = spec.get_committee_count(state, spec.get_current_epoch(state)) // spec.SLOTS_PER_EPOCH 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)): - for index in range(spec.COMMITTEES_PER_SLOT): + slot_start_index = spec.get_slot_start_index(state, slot_to_attest) + for i in range(committees_per_slot): + index = (slot_start_index + i) % spec.MAX_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: + committees_per_slot = spec.get_committee_count(state, spec.get_previous_epoch(state)) // spec.SLOTS_PER_EPOCH slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 - for index in range(spec.COMMITTEES_PER_SLOT): + slot_start_index = spec.get_slot_start_index(state, slot_to_attest) + for i in range(committees_per_slot): + index = (slot_start_index + i) % spec.MAX_COMMITTEES_PER_SLOT prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest, index=index) block.body.attestations.append(prev_attestation) 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 b3952b7ea..87024a21d 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 @@ -122,6 +122,12 @@ def test_old_source_epoch(spec, state): yield from run_attestation_processing(spec, state, attestation, False) +@with_all_phases +@spec_state_test +def test_wrong_index(spec, state): + pass + + @with_all_phases @spec_state_test @never_bls @@ -130,7 +136,7 @@ def test_invalid_index(spec, state): state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY # off by one (with respect to valid range) on purpose - attestation.data.index = spec.COMMITTEES_PER_SLOT + attestation.data.index = spec.MAX_COMMITTEES_PER_SLOT yield from run_attestation_processing(spec, state, attestation, False) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 4e0085076..abd8f2c17 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -26,8 +26,11 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support remaining_balance = total_balance * 2 // 3 start_slot = spec.compute_start_slot_of_epoch(epoch) + committees_per_slot = spec.get_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH): - for index in range(spec.COMMITTEES_PER_SLOT): + slot_start_index = spec.get_slot_start_index(state, slot) + for i in range(committees_per_slot): + index = (slot_start_index + i) % spec.MAX_COMMITTEES_PER_SLOT # 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 remaining_balance < 0: