Merge pull request #2406 from ethereum/sync-seed
remove sync committee seed and restrict period calculation boundaries
This commit is contained in:
commit
9a0be85b1e
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue