Merge pull request #2406 from ethereum/sync-seed

remove sync committee seed and restrict period calculation boundaries
This commit is contained in:
Danny Ryan 2021-05-12 12:17:42 -06:00 committed by GitHub
commit 9a0be85b1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 102 additions and 127 deletions

View File

@ -32,8 +32,8 @@
- [`add_flag`](#add_flag) - [`add_flag`](#add_flag)
- [`has_flag`](#has_flag) - [`has_flag`](#has_flag)
- [Beacon state accessors](#beacon-state-accessors) - [Beacon state accessors](#beacon-state-accessors)
- [`get_sync_committee_indices`](#get_sync_committee_indices) - [`get_next_sync_committee_indices`](#get_next_sync_committee_indices)
- [`get_sync_committee`](#get_sync_committee) - [`get_next_sync_committee`](#get_next_sync_committee)
- [`get_base_reward_per_increment`](#get_base_reward_per_increment) - [`get_base_reward_per_increment`](#get_base_reward_per_increment)
- [`get_base_reward`](#get_base_reward) - [`get_base_reward`](#get_base_reward)
- [`get_unslashed_participating_indices`](#get_unslashed_participating_indices) - [`get_unslashed_participating_indices`](#get_unslashed_participating_indices)
@ -270,22 +270,20 @@ def has_flag(flags: ParticipationFlags, flag_index: int) -> bool:
### Beacon state accessors ### Beacon state accessors
#### `get_sync_committee_indices` #### `get_next_sync_committee_indices`
```python ```python
def get_sync_committee_indices(state: BeaconState, epoch: Epoch) -> Sequence[ValidatorIndex]: def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
""" """
Return the sequence of sync committee indices (which may include duplicate indices) Return the sequence of sync committee indices (which may include duplicate indices)
for a given ``state`` and ``epoch``. for the next sync committee, given a ``state`` at a sync committee period boundary.
Note: This function is not stable during a sync committee period as
a validator's effective balance may change enough to affect the sampling.
""" """
epoch = Epoch(get_current_epoch(state) + 1)
MAX_RANDOM_BYTE = 2**8 - 1 MAX_RANDOM_BYTE = 2**8 - 1
base_epoch = Epoch((max(epoch // EPOCHS_PER_SYNC_COMMITTEE_PERIOD, 1) - 1) * EPOCHS_PER_SYNC_COMMITTEE_PERIOD) active_validator_indices = get_active_validator_indices(state, epoch)
active_validator_indices = get_active_validator_indices(state, base_epoch)
active_validator_count = uint64(len(active_validator_indices)) active_validator_count = uint64(len(active_validator_indices))
seed = get_seed(state, base_epoch, DOMAIN_SYNC_COMMITTEE) seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
i = 0 i = 0
sync_committee_indices: List[ValidatorIndex] = [] sync_committee_indices: List[ValidatorIndex] = []
while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE: while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE:
@ -299,25 +297,25 @@ def get_sync_committee_indices(state: BeaconState, epoch: Epoch) -> Sequence[Val
return sync_committee_indices return sync_committee_indices
``` ```
#### `get_sync_committee` #### `get_next_sync_committee`
```python ```python
def get_sync_committee(state: BeaconState, epoch: Epoch) -> SyncCommittee: def get_next_sync_committee(state: BeaconState) -> SyncCommittee:
""" """
Return the sync committee for a given ``state`` and ``epoch``. Return the *next* sync committee for a given ``state``.
``SyncCommittee`` contains an aggregate pubkey that enables ``SyncCommittee`` contains an aggregate pubkey that enables
resource-constrained clients to save some computation when verifying resource-constrained clients to save some computation when verifying
the sync committee's signature. the sync committee's signature.
``SyncCommittee`` can also contain duplicate pubkeys, when ``get_sync_committee_indices`` ``SyncCommittee`` can also contain duplicate pubkeys, when ``get_next_sync_committee_indices``
returns duplicate indices. Implementations must take care when handling returns duplicate indices. Implementations must take care when handling
optimizations relating to aggregation and verification in the presence of duplicates. optimizations relating to aggregation and verification in the presence of duplicates.
Note: This function should only be called at sync committee period boundaries, as Note: This function should only be called at sync committee period boundaries, as
``get_sync_committee_indices`` is not stable within a given period. ``get_next_sync_committee_indices`` is not stable within a given period.
""" """
indices = get_sync_committee_indices(state, epoch) indices = get_next_sync_committee_indices(state)
pubkeys = [state.validators[index].pubkey for index in indices] pubkeys = [state.validators[index].pubkey for index in indices]
aggregate_pubkey = bls.AggregatePKs(pubkeys) aggregate_pubkey = bls.AggregatePKs(pubkeys)
return SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=aggregate_pubkey) return SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=aggregate_pubkey)
@ -690,7 +688,7 @@ def process_sync_committee_updates(state: BeaconState) -> None:
next_epoch = get_current_epoch(state) + Epoch(1) next_epoch = get_current_epoch(state) + Epoch(1)
if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0: if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
state.current_sync_committee = state.next_sync_committee state.current_sync_committee = state.next_sync_committee
state.next_sync_committee = get_sync_committee(state, next_epoch + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) state.next_sync_committee = get_next_sync_committee(state)
``` ```
## Initialize state for pure Altair testnets and test vectors ## Initialize state for pure Altair testnets and test vectors
@ -735,8 +733,9 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
state.genesis_validators_root = hash_tree_root(state.validators) state.genesis_validators_root = hash_tree_root(state.validators)
# [New in Altair] Fill in sync committees # [New in Altair] Fill in sync committees
state.current_sync_committee = get_sync_committee(state, get_current_epoch(state)) # Note: A duplicate committee is assigned for the current and next committee at genesis
state.next_sync_committee = get_sync_committee(state, get_current_epoch(state) + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) state.current_sync_committee = get_next_sync_committee(state)
state.next_sync_committee = get_next_sync_committee(state)
return state return state
``` ```

View File

@ -84,8 +84,10 @@ def upgrade_to_altair(pre: phase0.BeaconState) -> BeaconState:
# Inactivity # Inactivity
inactivity_scores=[uint64(0) for _ in range(len(pre.validators))], inactivity_scores=[uint64(0) for _ in range(len(pre.validators))],
) )
# Fill in sync committees # Fill in sync committees
post.current_sync_committee = get_sync_committee(post, get_current_epoch(post)) # Note: A duplicate committee is assigned for the current and next committee at the fork boundary
post.next_sync_committee = get_sync_committee(post, get_current_epoch(post) + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) post.current_sync_committee = get_next_sync_committee(post)
post.next_sync_committee = get_next_sync_committee(post)
return post return post
``` ```

View File

@ -7,7 +7,6 @@ from eth2spec.test.helpers.block_processing import run_block_processing_to
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
state_transition_and_sign_block, state_transition_and_sign_block,
transition_to, transition_to,
next_epoch,
) )
from eth2spec.test.helpers.constants import ( from eth2spec.test.helpers.constants import (
MAINNET, MINIMAL, MAINNET, MINIMAL,
@ -50,9 +49,9 @@ def get_committee_indices(spec, state, duplicates=False):
""" """
state = state.copy() state = state.copy()
current_epoch = spec.get_current_epoch(state) current_epoch = spec.get_current_epoch(state)
randao_index = current_epoch % spec.EPOCHS_PER_HISTORICAL_VECTOR randao_index = (current_epoch + 1) % spec.EPOCHS_PER_HISTORICAL_VECTOR
while True: while True:
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) committee = spec.get_next_sync_committee_indices(state)
if duplicates: if duplicates:
if len(committee) != len(set(committee)): if len(committee) != len(set(committee)):
return committee return committee
@ -62,23 +61,32 @@ def get_committee_indices(spec, state, duplicates=False):
state.randao_mixes[randao_index] = hash(state.randao_mixes[randao_index]) state.randao_mixes[randao_index] = hash(state.randao_mixes[randao_index])
def compute_committee_indices(spec, state, committee):
"""
Given a ``committee``, calculate and return the related indices
"""
all_pubkeys = [v.pubkey for v in state.validators]
committee_indices = [all_pubkeys.index(pubkey) for pubkey in committee.pubkeys]
return committee_indices
@with_altair_and_later @with_altair_and_later
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_invalid_signature_missing_participant(spec, state): def test_invalid_signature_missing_participant(spec, state):
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
rng = random.Random(2020) rng = random.Random(2020)
random_participant = rng.choice(committee) random_participant = rng.choice(committee_indices)
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
# Exclude one participant whose signature was included. # Exclude one participant whose signature was included.
block.body.sync_aggregate = spec.SyncAggregate( block.body.sync_aggregate = spec.SyncAggregate(
sync_committee_bits=[index != random_participant for index in committee], sync_committee_bits=[index != random_participant for index in committee_indices],
sync_committee_signature=compute_aggregate_sync_committee_signature( sync_committee_signature=compute_aggregate_sync_committee_signature(
spec, spec,
state, state,
block.slot - 1, block.slot - 1,
committee, # full committee signs committee_indices, # full committee signs
) )
) )
yield from run_sync_committee_processing(spec, state, block, expect_exception=True) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
@ -88,31 +96,38 @@ def test_invalid_signature_missing_participant(spec, state):
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_invalid_signature_extra_participant(spec, state): def test_invalid_signature_extra_participant(spec, state):
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
rng = random.Random(3030) rng = random.Random(3030)
random_participant = rng.choice(committee) random_participant = rng.choice(committee_indices)
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
# Exclude one signature even though the block claims the entire committee participated. # Exclude one signature even though the block claims the entire committee participated.
block.body.sync_aggregate = spec.SyncAggregate( block.body.sync_aggregate = spec.SyncAggregate(
sync_committee_bits=[True] * len(committee), sync_committee_bits=[True] * len(committee_indices),
sync_committee_signature=compute_aggregate_sync_committee_signature( sync_committee_signature=compute_aggregate_sync_committee_signature(
spec, spec,
state, state,
block.slot - 1, block.slot - 1,
[index for index in committee if index != random_participant], [index for index in committee_indices if index != random_participant],
) )
) )
yield from run_sync_committee_processing(spec, state, block, expect_exception=True) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def compute_sync_committee_inclusion_reward(spec, state, participant_index, committee, committee_bits): def compute_sync_committee_inclusion_reward(spec,
state,
participant_index,
committee_indices,
committee_bits):
total_active_increments = spec.get_total_active_balance(state) // spec.EFFECTIVE_BALANCE_INCREMENT total_active_increments = spec.get_total_active_balance(state) // spec.EFFECTIVE_BALANCE_INCREMENT
total_base_rewards = spec.Gwei(spec.get_base_reward_per_increment(state) * total_active_increments) total_base_rewards = spec.Gwei(spec.get_base_reward_per_increment(state) * total_active_increments)
max_epoch_rewards = spec.Gwei(total_base_rewards * spec.SYNC_REWARD_WEIGHT // spec.WEIGHT_DENOMINATOR) max_epoch_rewards = spec.Gwei(total_base_rewards * spec.SYNC_REWARD_WEIGHT // spec.WEIGHT_DENOMINATOR)
included_indices = [index for index, bit in zip(committee, committee_bits) if bit] included_indices = [index for index, bit in zip(committee_indices, committee_bits) if bit]
max_slot_rewards = spec.Gwei(max_epoch_rewards * len(included_indices) // len(committee) // spec.SLOTS_PER_EPOCH) max_slot_rewards = spec.Gwei(
max_epoch_rewards * len(included_indices)
// len(committee_indices) // spec.SLOTS_PER_EPOCH
)
# Compute the participant and proposer sync rewards # Compute the participant and proposer sync rewards
committee_effective_balance = sum([state.validators[index].effective_balance for index in included_indices]) committee_effective_balance = sum([state.validators[index].effective_balance for index in included_indices])
@ -121,23 +136,23 @@ def compute_sync_committee_inclusion_reward(spec, state, participant_index, comm
return spec.Gwei(max_slot_rewards * effective_balance // committee_effective_balance) return spec.Gwei(max_slot_rewards * effective_balance // committee_effective_balance)
def compute_sync_committee_participant_reward(spec, state, participant_index, committee, committee_bits): def compute_sync_committee_participant_reward(spec, state, participant_index, committee_indices, committee_bits):
included_indices = [index for index, bit in zip(committee, committee_bits) if bit] included_indices = [index for index, bit in zip(committee_indices, committee_bits) if bit]
multiplicities = Counter(included_indices) multiplicities = Counter(included_indices)
inclusion_reward = compute_sync_committee_inclusion_reward( inclusion_reward = compute_sync_committee_inclusion_reward(
spec, state, participant_index, committee, committee_bits, spec, state, participant_index, committee_indices, committee_bits,
) )
return spec.Gwei(inclusion_reward * multiplicities[participant_index]) return spec.Gwei(inclusion_reward * multiplicities[participant_index])
def compute_sync_committee_proposer_reward(spec, state, committee, committee_bits): def compute_sync_committee_proposer_reward(spec, state, committee_indices, committee_bits):
proposer_reward = 0 proposer_reward = 0
for index, bit in zip(committee, committee_bits): for index, bit in zip(committee_indices, committee_bits):
if not bit: if not bit:
continue continue
inclusion_reward = compute_sync_committee_inclusion_reward( inclusion_reward = compute_sync_committee_inclusion_reward(
spec, state, index, committee, committee_bits, spec, state, index, committee_indices, committee_bits,
) )
proposer_reward_denominator = ( proposer_reward_denominator = (
(spec.WEIGHT_DENOMINATOR - spec.PROPOSER_WEIGHT) (spec.WEIGHT_DENOMINATOR - spec.PROPOSER_WEIGHT)
@ -148,15 +163,15 @@ def compute_sync_committee_proposer_reward(spec, state, committee, committee_bit
return proposer_reward return proposer_reward
def validate_sync_committee_rewards(spec, pre_state, post_state, committee, committee_bits, proposer_index): def validate_sync_committee_rewards(spec, pre_state, post_state, committee_indices, committee_bits, proposer_index):
for index in range(len(post_state.validators)): for index in range(len(post_state.validators)):
reward = 0 reward = 0
if index in committee: if index in committee_indices:
reward += compute_sync_committee_participant_reward( reward += compute_sync_committee_participant_reward(
spec, spec,
pre_state, pre_state,
index, index,
committee, committee_indices,
committee_bits, committee_bits,
) )
@ -164,14 +179,14 @@ def validate_sync_committee_rewards(spec, pre_state, post_state, committee, comm
reward += compute_sync_committee_proposer_reward( reward += compute_sync_committee_proposer_reward(
spec, spec,
pre_state, pre_state,
committee, committee_indices,
committee_bits, committee_bits,
) )
assert post_state.balances[index] == pre_state.balances[index] + reward assert post_state.balances[index] == pre_state.balances[index] + reward
def run_successful_sync_committee_test(spec, state, committee, committee_bits): def run_successful_sync_committee_test(spec, state, committee_indices, committee_bits):
pre_state = state.copy() pre_state = state.copy()
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
@ -181,7 +196,7 @@ def run_successful_sync_committee_test(spec, state, committee, committee_bits):
spec, spec,
state, state,
block.slot - 1, block.slot - 1,
[index for index, bit in zip(committee, committee_bits) if bit], [index for index, bit in zip(committee_indices, committee_bits) if bit],
) )
) )
@ -191,7 +206,7 @@ def run_successful_sync_committee_test(spec, state, committee, committee_bits):
spec, spec,
pre_state, pre_state,
state, state,
committee, committee_indices,
committee_bits, committee_bits,
block.proposer_index, block.proposer_index,
) )
@ -201,60 +216,60 @@ def run_successful_sync_committee_test(spec, state, committee, committee_bits):
@with_configs([MINIMAL], reason="to create nonduplicate committee") @with_configs([MINIMAL], reason="to create nonduplicate committee")
@spec_state_test @spec_state_test
def test_sync_committee_rewards_nonduplicate_committee(spec, state): def test_sync_committee_rewards_nonduplicate_committee(spec, state):
committee = get_committee_indices(spec, state, duplicates=False) committee_indices = get_committee_indices(spec, state, duplicates=False)
committee_size = len(committee) committee_size = len(committee_indices)
committee_bits = [True] * committee_size committee_bits = [True] * committee_size
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
# Preconditions of this test case # Preconditions of this test case
assert active_validator_count >= spec.SYNC_COMMITTEE_SIZE assert active_validator_count >= spec.SYNC_COMMITTEE_SIZE
assert committee_size == len(set(committee)) assert committee_size == len(set(committee_indices))
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits) yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
@with_altair_and_later @with_altair_and_later
@with_configs([MAINNET], reason="to create duplicate committee") @with_configs([MAINNET], reason="to create duplicate committee")
@spec_state_test @spec_state_test
def test_sync_committee_rewards_duplicate_committee(spec, state): def test_sync_committee_rewards_duplicate_committee(spec, state):
committee = get_committee_indices(spec, state, duplicates=True) committee_indices = get_committee_indices(spec, state, duplicates=True)
committee_size = len(committee) committee_size = len(committee_indices)
committee_bits = [True] * committee_size committee_bits = [True] * committee_size
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
# Preconditions of this test case # Preconditions of this test case
assert active_validator_count < spec.SYNC_COMMITTEE_SIZE assert active_validator_count < spec.SYNC_COMMITTEE_SIZE
assert committee_size > len(set(committee)) assert committee_size > len(set(committee_indices))
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits) yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
@with_altair_and_later @with_altair_and_later
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_sync_committee_rewards_not_full_participants(spec, state): def test_sync_committee_rewards_not_full_participants(spec, state):
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
rng = random.Random(1010) rng = random.Random(1010)
committee_bits = [rng.choice([True, False]) for _ in committee] committee_bits = [rng.choice([True, False]) for _ in committee_indices]
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits) yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
@with_altair_and_later @with_altair_and_later
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_sync_committee_rewards_empty_participants(spec, state): def test_sync_committee_rewards_empty_participants(spec, state):
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_bits = [False for _ in committee] committee_bits = [False for _ in committee_indices]
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits) yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
@with_altair_and_later @with_altair_and_later
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_invalid_signature_past_block(spec, state): def test_invalid_signature_past_block(spec, state):
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
blocks = [] blocks = []
for _ in range(2): for _ in range(2):
@ -262,12 +277,12 @@ def test_invalid_signature_past_block(spec, state):
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
# Valid sync committee signature here... # Valid sync committee signature here...
block.body.sync_aggregate = spec.SyncAggregate( block.body.sync_aggregate = spec.SyncAggregate(
sync_committee_bits=[True] * len(committee), sync_committee_bits=[True] * len(committee_indices),
sync_committee_signature=compute_aggregate_sync_committee_signature( sync_committee_signature=compute_aggregate_sync_committee_signature(
spec, spec,
state, state,
block.slot - 1, block.slot - 1,
committee, committee_indices,
) )
) )
@ -277,12 +292,12 @@ def test_invalid_signature_past_block(spec, state):
invalid_block = build_empty_block_for_next_slot(spec, state) invalid_block = build_empty_block_for_next_slot(spec, state)
# Invalid signature from a slot other than the previous # Invalid signature from a slot other than the previous
invalid_block.body.sync_aggregate = spec.SyncAggregate( invalid_block.body.sync_aggregate = spec.SyncAggregate(
sync_committee_bits=[True] * len(committee), sync_committee_bits=[True] * len(committee_indices),
sync_committee_signature=compute_aggregate_sync_committee_signature( sync_committee_signature=compute_aggregate_sync_committee_signature(
spec, spec,
state, state,
invalid_block.slot - 2, invalid_block.slot - 2,
committee, committee_indices,
) )
) )
@ -307,19 +322,18 @@ def test_invalid_signature_previous_committee(spec, state):
transition_to(spec, state, slot_in_future_sync_committee_period) transition_to(spec, state, slot_in_future_sync_committee_period)
# Use the previous sync committee to produce the signature. # Use the previous sync committee to produce the signature.
pubkeys = [validator.pubkey for validator in state.validators]
# Ensure that the pubkey sets are different. # Ensure that the pubkey sets are different.
assert set(old_sync_committee.pubkeys) != set(state.current_sync_committee.pubkeys) assert set(old_sync_committee.pubkeys) != set(state.current_sync_committee.pubkeys)
committee = [pubkeys.index(pubkey) for pubkey in old_sync_committee.pubkeys] committee_indices = compute_committee_indices(spec, state, old_sync_committee)
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
block.body.sync_aggregate = spec.SyncAggregate( block.body.sync_aggregate = spec.SyncAggregate(
sync_committee_bits=[True] * len(committee), sync_committee_bits=[True] * len(committee_indices),
sync_committee_signature=compute_aggregate_sync_committee_signature( sync_committee_signature=compute_aggregate_sync_committee_signature(
spec, spec,
state, state,
block.slot - 1, block.slot - 1,
committee, committee_indices,
) )
) )
@ -345,15 +359,13 @@ def test_valid_signature_future_committee(spec, state):
transition_to(spec, state, slot_in_future_sync_committee_period) transition_to(spec, state, slot_in_future_sync_committee_period)
sync_committee = state.current_sync_committee sync_committee = state.current_sync_committee
next_sync_committee = state.next_sync_committee
expected_sync_committee = spec.get_sync_committee(state, epoch_in_future_sync_committee_period) assert next_sync_committee != sync_committee
assert sync_committee == expected_sync_committee
assert sync_committee != old_current_sync_committee assert sync_committee != old_current_sync_committee
assert sync_committee != old_next_sync_committee assert sync_committee != old_next_sync_committee
pubkeys = [validator.pubkey for validator in state.validators] committee_indices = compute_committee_indices(spec, state, sync_committee)
committee_indices = [pubkeys.index(pubkey) for pubkey in sync_committee.pubkeys]
block = build_empty_block_for_next_slot(spec, state) block = build_empty_block_for_next_slot(spec, state)
block.body.sync_aggregate = spec.SyncAggregate( block.body.sync_aggregate = spec.SyncAggregate(
@ -367,43 +379,3 @@ def test_valid_signature_future_committee(spec, state):
) )
yield from run_sync_committee_processing(spec, state, block) yield from run_sync_committee_processing(spec, state, block)
@with_altair_and_later
@spec_state_test
def test_sync_committee_is_only_computed_at_epoch_boundary(spec, state):
"""
Sync committees can only be computed at sync committee period boundaries.
Ensure a client respects the committee in the state (assumed to be derived
in the correct way).
"""
current_epoch = spec.get_current_epoch(state)
# use a "synthetic" committee to simulate the situation
# where ``spec.get_sync_committee`` at the sync committee
# period epoch boundary would have diverged some epochs into the
# period; ``aggregate_pubkey`` is not relevant to this test
pubkeys = []
committee_indices = []
i = 0
active_validator_count = len(spec.get_active_validator_indices(state, current_epoch))
while len(pubkeys) < spec.SYNC_COMMITTEE_SIZE:
v = state.validators[i % active_validator_count]
if spec.is_active_validator(v, current_epoch):
pubkeys.append(v.pubkey)
committee_indices.append(i)
i += 1
synthetic_committee = spec.SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=spec.BLSPubkey())
state.current_sync_committee = synthetic_committee
assert spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD > 3
for _ in range(3):
next_epoch(spec, state)
committee = get_committee_indices(spec, state)
assert committee != committee_indices
committee_size = len(committee_indices)
committee_bits = [True] * committee_size
yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)

View File

@ -39,8 +39,7 @@ def run_sync_committees_progress_test(spec, state):
# Can compute the third committee having computed final balances in the last epoch # Can compute the third committee having computed final balances in the last epoch
# of this `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` # of this `EPOCHS_PER_SYNC_COMMITTEE_PERIOD`
current_epoch = spec.get_current_epoch(state) third_sync_committee = spec.get_next_sync_committee(state)
third_sync_committee = spec.get_sync_committee(state, current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD)
assert state.current_sync_committee == second_sync_committee assert state.current_sync_committee == second_sync_committee
assert state.next_sync_committee == third_sync_committee assert state.next_sync_committee == third_sync_committee

View File

@ -18,7 +18,8 @@ from eth2spec.test.context import (
def run_sync_committee_sanity_test(spec, state, fraction_full=1.0): def run_sync_committee_sanity_test(spec, state, fraction_full=1.0):
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) all_pubkeys = [v.pubkey for v in state.validators]
committee = [all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys]
participants = random.sample(committee, int(len(committee) * fraction_full)) participants = random.sample(committee, int(len(committee) * fraction_full))
yield 'pre', state yield 'pre', state

View File

@ -46,7 +46,8 @@ def test_process_light_client_update_not_updated(spec, state):
body_root=signed_block.message.body.hash_tree_root(), body_root=signed_block.message.body.hash_tree_root(),
) )
# Sync committee signing the header # Sync committee signing the header
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) all_pubkeys = [v.pubkey for v in state.validators]
committee = [all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys]
sync_committee_bits = [True] * len(committee) sync_committee_bits = [True] * len(committee)
sync_committee_signature = compute_aggregate_sync_committee_signature( sync_committee_signature = compute_aggregate_sync_committee_signature(
spec, spec,
@ -111,7 +112,8 @@ def test_process_light_client_update_timeout(spec, state):
) )
# Sync committee signing the finalized_block_header # Sync committee signing the finalized_block_header
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) all_pubkeys = [v.pubkey for v in state.validators]
committee = [all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys]
sync_committee_bits = [True] * len(committee) sync_committee_bits = [True] * len(committee)
sync_committee_signature = compute_aggregate_sync_committee_signature( sync_committee_signature = compute_aggregate_sync_committee_signature(
spec, spec,
@ -190,7 +192,8 @@ def test_process_light_client_update_finality_updated(spec, state):
) )
# Sync committee signing the finalized_block_header # Sync committee signing the finalized_block_header
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) all_pubkeys = [v.pubkey for v in state.validators]
committee = [all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys]
sync_committee_bits = [True] * len(committee) sync_committee_bits = [True] * len(committee)
sync_committee_signature = compute_aggregate_sync_committee_signature( sync_committee_signature = compute_aggregate_sync_committee_signature(
spec, spec,

View File

@ -69,9 +69,8 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
if spec.fork not in FORKS_BEFORE_ALTAIR: if spec.fork not in FORKS_BEFORE_ALTAIR:
# Fill in sync committees # Fill in sync committees
state.current_sync_committee = spec.get_sync_committee(state, spec.get_current_epoch(state)) # Note: A duplicate committee is assigned for the current and next committee at genesis
state.next_sync_committee = ( state.current_sync_committee = spec.get_next_sync_committee(state)
spec.get_sync_committee(state, spec.get_current_epoch(state) + spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD) state.next_sync_committee = spec.get_next_sync_committee(state)
)
return state return state