Ensure non-zero bits for each aggregate committee

This commit is contained in:
Mikhail Kalinin 2024-11-04 17:40:10 +06:00
parent 1b408e9354
commit a3d4dbaafa
2 changed files with 65 additions and 4 deletions

View File

@ -56,6 +56,7 @@
- [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit) - [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit)
- [New `get_consolidation_churn_limit`](#new-get_consolidation_churn_limit) - [New `get_consolidation_churn_limit`](#new-get_consolidation_churn_limit)
- [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw) - [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw)
- [Modified `get_indexed_attestation`](#modified-get_indexed_attestation)
- [Modified `get_attesting_indices`](#modified-get_attesting_indices) - [Modified `get_attesting_indices`](#modified-get_attesting_indices)
- [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices) - [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices)
- [Beacon state mutators](#beacon-state-mutators) - [Beacon state mutators](#beacon-state-mutators)
@ -572,6 +573,25 @@ def get_pending_balance_to_withdraw(state: BeaconState, validator_index: Validat
) )
``` ```
#### Modified `get_indexed_attestation`
*Note*: The function is modified to use the new `get_attesting_indices`.
```python
def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> IndexedAttestation:
"""
Return the indexed attestation corresponding to ``attestation``.
"""
# [Modified in Electra:EIP7549]
attesting_indices = get_attesting_indices(state, attestation)
return IndexedAttestation(
attesting_indices=sorted(attesting_indices),
data=attestation.data,
signature=attestation.signature,
)
```
#### Modified `get_attesting_indices` #### Modified `get_attesting_indices`
*Note*: The function `get_attesting_indices` is modified to support EIP7549. *Note*: The function `get_attesting_indices` is modified to support EIP7549.
@ -1254,6 +1274,8 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
###### Modified `process_attestation` ###### Modified `process_attestation`
*Note*: The function is modified to support EIP7549.
```python ```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None: def process_attestation(state: BeaconState, attestation: Attestation) -> None:
data = attestation.data data = attestation.data
@ -1264,18 +1286,24 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
# [Modified in Electra:EIP7549] # [Modified in Electra:EIP7549]
assert data.index == 0 assert data.index == 0
committee_indices = get_committee_indices(attestation.committee_bits) committee_indices = get_committee_indices(attestation.committee_bits)
participants_count = 0 committee_offset = 0
for index in committee_indices: for index in committee_indices:
assert index < get_committee_count_per_slot(state, data.target.epoch) assert index < get_committee_count_per_slot(state, data.target.epoch)
committee = get_beacon_committee(state, data.slot, index) committee = get_beacon_committee(state, data.slot, index)
participants_count += len(committee) committee_attesters = set(
attester_index for i, attester_index in enumerate(committee)
if attestation.aggregation_bits[committee_offset + i]
)
assert len(committee_attesters) > 0
committee_offset += len(committee)
assert len(attestation.aggregation_bits) == participants_count # Bitfield length matches total number of participants
assert len(attestation.aggregation_bits) == committee_offset
# Participation flag indices # Participation flag indices
participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot)
# Verify signature # Verify signature [Modified in Electra:EIP7549]
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
# Update epoch participation flags # Update epoch participation flags
@ -1285,6 +1313,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
epoch_participation = state.previous_epoch_participation epoch_participation = state.previous_epoch_participation
proposer_reward_numerator = 0 proposer_reward_numerator = 0
# [Modified in Electra:EIP7549]
for index in get_attesting_indices(state, attestation): for index in get_attesting_indices(state, attestation):
for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):

View File

@ -1,12 +1,15 @@
from eth2spec.test.helpers.constants import MINIMAL
from eth2spec.test.context import ( from eth2spec.test.context import (
always_bls, always_bls,
spec_state_test, spec_state_test,
with_electra_and_later, with_electra_and_later,
with_presets,
) )
from eth2spec.test.helpers.attestations import ( from eth2spec.test.helpers.attestations import (
run_attestation_processing, run_attestation_processing,
get_valid_attestation, get_valid_attestation,
sign_attestation, sign_attestation,
get_empty_eip7549_aggregation_bits,
) )
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
next_slots, next_slots,
@ -79,3 +82,32 @@ def test_invalid_nonset_committe_bits(spec, state):
attestation.committee_bits[committee_index] = 0 attestation.committee_bits[committee_index] = 0
yield from run_attestation_processing(spec, state, attestation, valid=False) yield from run_attestation_processing(spec, state, attestation, valid=False)
@with_electra_and_later
@spec_state_test
def test_invalid_nonset_bits_for_one_committee(spec, state):
"""
EIP-7549 test
"""
# Attestation with full committee participating
committee_0 = spec.get_beacon_committee(state, state.slot, 0)
attestation_1 = get_valid_attestation(spec, state, index=1, signed=True)
# Create an on chain aggregate
aggregate = spec.Attestation(data=attestation_1.data, signature=attestation_1.signature)
aggregate.committee_bits[0] = True
aggregate.committee_bits[1] = True
aggregate.aggregation_bits = get_empty_eip7549_aggregation_bits(
spec, state, aggregate.committee_bits, aggregate.data.slot
)
committee_offset = len(committee_0)
for i in range(len(attestation_1.aggregation_bits)):
aggregate.aggregation_bits[committee_offset + i] = attestation_1.aggregation_bits[i]
# Check that only one committee is presented
assert spec.get_attesting_indices(state, aggregate) == spec.get_attesting_indices(state, attestation_1)
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, aggregate, valid=False)