Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eip7549: Ensure non-zero bits for each committee bitfield comprising an aggregate #4002

Merged
merged 5 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions specs/electra/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,8 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:

###### Modified `process_attestation`

*Note*: The function is modified to support EIP7549.

```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
data = attestation.data
Expand All @@ -1265,13 +1267,19 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
# [Modified in Electra:EIP7549]
assert data.index == 0
committee_indices = get_committee_indices(attestation.committee_bits)
participants_count = 0
for index in committee_indices:
assert index < get_committee_count_per_slot(state, data.target.epoch)
committee = get_beacon_committee(state, data.slot, index)
participants_count += len(committee)
committee_offset = 0
for committee_index in committee_indices:
assert committee_index < get_committee_count_per_slot(state, data.target.epoch)
committee = get_beacon_committee(state, data.slot, committee_index)
committee_attesters = set(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not that important but this part is quite similar to the logic in get_attesting_indices(). I think we can extract common part to a separate util function.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at it as well but it doesn’t seem there is a good way to decompose

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 = get_attestation_participation_flag_indices(state, data, state.slot - data.slot)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def test_invalid_nonset_committee_bits(spec, state):

@with_electra_and_later
@spec_state_test
@with_presets([MINIMAL], "need multiple committees per slot")
def test_invalid_nonset_multiple_committee_bits(spec, state):
"""
EIP-7549 test
Expand Down Expand Up @@ -148,3 +149,33 @@ def test_one_committee_with_gap(spec, state):
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)

yield from run_attestation_processing(spec, state, attestation)


@with_electra_and_later
@spec_state_test
@with_presets([MINIMAL], "need multiple committees per slot")
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)