diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 34a33469e..367858340 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -32,8 +32,8 @@ - [`add_flag`](#add_flag) - [`has_flag`](#has_flag) - [Beacon state accessors](#beacon-state-accessors) - - [`get_sync_committee_indices`](#get_sync_committee_indices) - - [`get_sync_committee`](#get_sync_committee) + - [`get_next_sync_committee_indices`](#get_next_sync_committee_indices) + - [`get_next_sync_committee`](#get_next_sync_committee) - [`get_base_reward_per_increment`](#get_base_reward_per_increment) - [`get_base_reward`](#get_base_reward) - [`get_unslashed_participating_indices`](#get_unslashed_participating_indices) @@ -270,22 +270,20 @@ def has_flag(flags: ParticipationFlags, flag_index: int) -> bool: ### Beacon state accessors -#### `get_sync_committee_indices` +#### `get_next_sync_committee_indices` ```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) - for a given ``state`` and ``epoch``. - - Note: This function is not stable during a sync committee period as - a validator's effective balance may change enough to affect the sampling. + for the next sync committee, given a ``state`` at a sync committee period boundary. """ + epoch = Epoch(get_current_epoch(state) + 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, base_epoch) + active_validator_indices = get_active_validator_indices(state, epoch) 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 sync_committee_indices: List[ValidatorIndex] = [] 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 ``` -#### `get_sync_committee` +#### `get_next_sync_committee` ```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 resource-constrained clients to save some computation when verifying 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 optimizations relating to aggregation and verification in the presence of duplicates. 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] aggregate_pubkey = bls.AggregatePKs(pubkeys) 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) if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0: 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 @@ -735,8 +733,9 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, state.genesis_validators_root = hash_tree_root(state.validators) # [New in Altair] Fill in sync committees - state.current_sync_committee = get_sync_committee(state, get_current_epoch(state)) - state.next_sync_committee = get_sync_committee(state, get_current_epoch(state) + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) + # Note: A duplicate committee is assigned for the current and next committee at genesis + state.current_sync_committee = get_next_sync_committee(state) + state.next_sync_committee = get_next_sync_committee(state) return state ``` diff --git a/specs/altair/fork.md b/specs/altair/fork.md index ac2258def..2c8b9f855 100644 --- a/specs/altair/fork.md +++ b/specs/altair/fork.md @@ -84,8 +84,10 @@ def upgrade_to_altair(pre: phase0.BeaconState) -> BeaconState: # Inactivity inactivity_scores=[uint64(0) for _ in range(len(pre.validators))], ) + # Fill in sync committees - post.current_sync_committee = get_sync_committee(post, get_current_epoch(post)) - post.next_sync_committee = get_sync_committee(post, get_current_epoch(post) + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) + # Note: A duplicate committee is assigned for the current and next committee at the fork boundary + post.current_sync_committee = get_next_sync_committee(post) + post.next_sync_committee = get_next_sync_committee(post) return post ``` diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py index 2e5d62d11..e3ee32a93 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py @@ -7,7 +7,6 @@ from eth2spec.test.helpers.block_processing import run_block_processing_to from eth2spec.test.helpers.state import ( state_transition_and_sign_block, transition_to, - next_epoch, ) from eth2spec.test.helpers.constants import ( MAINNET, MINIMAL, @@ -50,9 +49,9 @@ def get_committee_indices(spec, state, duplicates=False): """ state = state.copy() 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: - committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) + committee = spec.get_next_sync_committee_indices(state) if duplicates: if len(committee) != len(set(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]) +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 @spec_state_test @always_bls 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) - random_participant = rng.choice(committee) + random_participant = rng.choice(committee_indices) block = build_empty_block_for_next_slot(spec, state) # Exclude one participant whose signature was included. 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( spec, state, block.slot - 1, - committee, # full committee signs + committee_indices, # full committee signs ) ) 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 @always_bls 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) - random_participant = rng.choice(committee) + random_participant = rng.choice(committee_indices) block = build_empty_block_for_next_slot(spec, state) # Exclude one signature even though the block claims the entire committee participated. 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( spec, state, 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) -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_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) - included_indices = [index for index, bit in zip(committee, committee_bits) if bit] - max_slot_rewards = spec.Gwei(max_epoch_rewards * len(included_indices) // len(committee) // spec.SLOTS_PER_EPOCH) + 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_indices) // spec.SLOTS_PER_EPOCH + ) # Compute the participant and proposer sync rewards 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) -def compute_sync_committee_participant_reward(spec, state, participant_index, committee, committee_bits): - included_indices = [index for index, bit in zip(committee, committee_bits) if bit] +def compute_sync_committee_participant_reward(spec, state, participant_index, committee_indices, committee_bits): + included_indices = [index for index, bit in zip(committee_indices, committee_bits) if bit] multiplicities = Counter(included_indices) 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]) -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 - for index, bit in zip(committee, committee_bits): + for index, bit in zip(committee_indices, committee_bits): if not bit: continue inclusion_reward = compute_sync_committee_inclusion_reward( - spec, state, index, committee, committee_bits, + spec, state, index, committee_indices, committee_bits, ) proposer_reward_denominator = ( (spec.WEIGHT_DENOMINATOR - spec.PROPOSER_WEIGHT) @@ -148,15 +163,15 @@ def compute_sync_committee_proposer_reward(spec, state, committee, committee_bit 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)): reward = 0 - if index in committee: + if index in committee_indices: reward += compute_sync_committee_participant_reward( spec, pre_state, index, - committee, + committee_indices, committee_bits, ) @@ -164,14 +179,14 @@ def validate_sync_committee_rewards(spec, pre_state, post_state, committee, comm reward += compute_sync_committee_proposer_reward( spec, pre_state, - committee, + committee_indices, committee_bits, ) 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() 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, state, 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, pre_state, state, - committee, + committee_indices, committee_bits, 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") @spec_state_test def test_sync_committee_rewards_nonduplicate_committee(spec, state): - committee = get_committee_indices(spec, state, duplicates=False) - committee_size = len(committee) + committee_indices = get_committee_indices(spec, state, duplicates=False) + committee_size = len(committee_indices) committee_bits = [True] * committee_size active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) # Preconditions of this test case 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_configs([MAINNET], reason="to create duplicate committee") @spec_state_test def test_sync_committee_rewards_duplicate_committee(spec, state): - committee = get_committee_indices(spec, state, duplicates=True) - committee_size = len(committee) + committee_indices = get_committee_indices(spec, state, duplicates=True) + committee_size = len(committee_indices) committee_bits = [True] * committee_size active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) # Preconditions of this test case 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 @spec_state_test @always_bls 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) - 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 @spec_state_test @always_bls def test_sync_committee_rewards_empty_participants(spec, state): - committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) - committee_bits = [False for _ in committee] + committee_indices = compute_committee_indices(spec, state, state.current_sync_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 @spec_state_test @always_bls 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 = [] 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) # Valid sync committee signature here... 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( spec, state, 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 signature from a slot other than the previous 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( spec, state, 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) # Use the previous sync committee to produce the signature. - pubkeys = [validator.pubkey for validator in state.validators] # Ensure that the pubkey sets are different. 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.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( spec, state, 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) 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 sync_committee == expected_sync_committee + assert next_sync_committee != sync_committee assert sync_committee != old_current_sync_committee assert sync_committee != old_next_sync_committee - pubkeys = [validator.pubkey for validator in state.validators] - committee_indices = [pubkeys.index(pubkey) for pubkey in sync_committee.pubkeys] + committee_indices = compute_committee_indices(spec, state, sync_committee) block = build_empty_block_for_next_slot(spec, state) 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) - - -@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) diff --git a/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py b/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py index c909c791c..6af16287c 100644 --- a/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py +++ b/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py @@ -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 # of this `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` - current_epoch = spec.get_current_epoch(state) - third_sync_committee = spec.get_sync_committee(state, current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD) + third_sync_committee = spec.get_next_sync_committee(state) assert state.current_sync_committee == second_sync_committee assert state.next_sync_committee == third_sync_committee diff --git a/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py index ffe743531..407455a0a 100644 --- a/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py @@ -18,7 +18,8 @@ from eth2spec.test.context import ( 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)) yield 'pre', state diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py index 932a46ca5..554cebda8 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py @@ -46,7 +46,8 @@ def test_process_light_client_update_not_updated(spec, state): body_root=signed_block.message.body.hash_tree_root(), ) # 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_signature = compute_aggregate_sync_committee_signature( spec, @@ -111,7 +112,8 @@ def test_process_light_client_update_timeout(spec, state): ) # 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_signature = compute_aggregate_sync_committee_signature( spec, @@ -190,7 +192,8 @@ def test_process_light_client_update_finality_updated(spec, state): ) # 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_signature = compute_aggregate_sync_committee_signature( spec, diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 4a34a5eb3..c57442766 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -69,9 +69,8 @@ def create_genesis_state(spec, validator_balances, activation_threshold): if spec.fork not in FORKS_BEFORE_ALTAIR: # Fill in sync committees - state.current_sync_committee = spec.get_sync_committee(state, spec.get_current_epoch(state)) - state.next_sync_committee = ( - spec.get_sync_committee(state, spec.get_current_epoch(state) + spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD) - ) + # Note: A duplicate committee is assigned for the current and next committee at genesis + state.current_sync_committee = spec.get_next_sync_committee(state) + state.next_sync_committee = spec.get_next_sync_committee(state) return state