From 702ac2885809cb1e772818591c6a5015def5c0e6 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 25 Mar 2024 16:19:11 +0600 Subject: [PATCH 1/2] eip7549: flatten aggregate_bits --- specs/_features/eip7549/beacon-chain.md | 15 ++++++++++----- specs/_features/eip7549/p2p-interface.md | 6 ++---- specs/_features/eip7549/validator.md | 15 ++++++++------- specs/phase0/p2p-interface.md | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/specs/_features/eip7549/beacon-chain.md b/specs/_features/eip7549/beacon-chain.md index 2382551e2..cac3a5723 100644 --- a/specs/_features/eip7549/beacon-chain.md +++ b/specs/_features/eip7549/beacon-chain.md @@ -44,7 +44,7 @@ This is the beacon chain specification to move the attestation committee index o ```python class Attestation(Container): - aggregation_bits: List[Bitlist[MAX_VALIDATORS_PER_COMMITTEE], MAX_COMMITTEES_PER_SLOT] # [Modified in EIP7549] + aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] # [Modified in EIP7549] data: AttestationData committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT] # [New in EIP7549] signature: BLSSignature @@ -83,12 +83,15 @@ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[V output = set() committee_indices = get_committee_indices(attestation.committee_bits) + committee_offset = 0 for index in committee_indices: - attesting_bits = attestation.aggregation_bits[index] committee = get_beacon_committee(state, attestation.data.slot, index) - committee_attesters = set(index for i, index in enumerate(committee) if attesting_bits[i]) + committee_attesters = set( + index for i, index in enumerate(committee) if attestation.aggregation_bits[committee_offset + i]) output = output.union(committee_attesters) + committee_offset += len(committee) + return output ``` @@ -106,11 +109,13 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: # [Modified in EIP7549] assert data.index == 0 committee_indices = get_committee_indices(attestation.committee_bits) - assert len(committee_indices) == len(attestation.aggregation_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) - assert len(attestation.aggregation_bits[index]) == len(committee) + participants_count += len(committee) + + assert len(attestation.aggregation_bits) == participants_count # Participation flag indices participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) diff --git a/specs/_features/eip7549/p2p-interface.md b/specs/_features/eip7549/p2p-interface.md index c7413ea4b..20aa291b3 100644 --- a/specs/_features/eip7549/p2p-interface.md +++ b/specs/_features/eip7549/p2p-interface.md @@ -36,19 +36,17 @@ The `beacon_aggregate_and_proof` and `beacon_attestation_{subnet_id}` topics are The following convenience variables are re-defined - `index = get_committee_indices(aggregate.committee_bits)[0]` -- `aggregation_bits = aggregate.aggregation_bits[0]` The following validations are added: -* [REJECT] `len(committee_indices) == len(aggregate.attestation_bits) == 1`, where `committee_indices = get_committee_indices(aggregate)`. +* [REJECT] `len(committee_indices) == 1`, where `committee_indices = get_committee_indices(aggregate)`. * [REJECT] `aggregate.data.index == 0` ###### `beacon_attestation_{subnet_id}` The following convenience variables are re-defined - `index = get_committee_indices(attestation.committee_bits)[0]` -- `aggregation_bits = attestation.aggregation_bits[0]` The following validations are added: -* [REJECT] `len(committee_indices) == len(attestation.attestation_bits) == 1`, where `committee_indices = get_committee_indices(attestation)`. +* [REJECT] `len(committee_indices) == 1`, where `committee_indices = get_committee_indices(attestation)`. * [REJECT] `attestation.data.index == 0` diff --git a/specs/_features/eip7549/validator.md b/specs/_features/eip7549/validator.md index 7278a1ebf..201c41c75 100644 --- a/specs/_features/eip7549/validator.md +++ b/specs/_features/eip7549/validator.md @@ -35,7 +35,11 @@ def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attesta aggregates = sorted(network_aggregates, key=lambda a: get_committee_indices(a.committee_bits)[0]) data = aggregates[0].data - aggregation_bits = [a.aggregation_bits[0] for a in aggregates] + aggregation_bits = Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT]() + for a in aggregates: + for b in a.aggregation_bits: + aggregation_bits.append(b) + signature = bls.Aggregate([a.signature for a in aggregates]) committee_indices = [get_committee_indices(a.committee_bits)[0] for a in aggregates] @@ -50,10 +54,8 @@ def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attesta #### Construct attestation - Set `attestation_data.index = 0`. -- Let `aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` of length `len(committee)`, where the bit of the index of the validator in the `committee` is set to `0b1`. -- Set `attestation.aggregation_bits = [aggregation_bits]`, a list of length 1 -- Let `committee_bits` be a `Bitvector[MAX_COMMITTEES_PER_SLOT]`, where the bit at the index associated with the validator's committee is set to `0b1` -- Set `attestation.committee_bits = committee_bits` +- Let `attestation.aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` of length `len(committee)`, where the bit of the index of the validator in the `committee` is set to `0b1`. +- Let `attestation.committee_bits` be a `Bitvector[MAX_COMMITTEES_PER_SLOT]`, where the bit at the index associated with the validator's committee is set to `0b1`. *Note*: Calling `get_attesting_indices(state, attestation)` should return a list of length equal to 1, containing `validator_index`. @@ -63,6 +65,5 @@ def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attesta - Set `attestation_data.index = 0`. - Let `aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` of length `len(committee)`, where each bit set from each individual attestation is set to `0b1`. -- Set `attestation.aggregation_bits = [aggregation_bits]`, a list of length 1 -- Set `attestation.committee_bits = committee_bits`, where `committee_bits` has the same value as in each individual attestation +- Set `attestation.committee_bits = committee_bits`, where `committee_bits` has the same value as in each individual attestation. diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index a34b34233..eb738ddaf 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -367,7 +367,7 @@ The following validations MUST pass before forwarding the `signed_aggregate_and_ - _[REJECT]_ The aggregate attestation's epoch matches its target -- i.e. `aggregate.data.target.epoch == compute_epoch_at_slot(aggregate.data.slot)` - _[REJECT]_ The number of aggregation bits matches the committee size -- i.e. - `len(aggregation_bits) == len(get_beacon_committee(state, aggregate.data.slot, aggregate.data.index))`. + `len(aggregation_bits) == len(get_beacon_committee(state, aggregate.data.slot, index))`. - _[REJECT]_ The aggregate attestation has participants -- that is, `len(get_attesting_indices(state, aggregate)) >= 1`. - _[IGNORE]_ A valid aggregate attestation defined by `hash_tree_root(aggregate.data)` whose `aggregation_bits` is a non-strict superset has _not_ already been seen. From bb8ba9c0456a7080917cd976210fa7c355c709b2 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 25 Mar 2024 19:20:58 +0600 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- specs/_features/eip7549/validator.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/_features/eip7549/validator.md b/specs/_features/eip7549/validator.md index 201c41c75..98310bc6f 100644 --- a/specs/_features/eip7549/validator.md +++ b/specs/_features/eip7549/validator.md @@ -54,7 +54,7 @@ def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attesta #### Construct attestation - Set `attestation_data.index = 0`. -- Let `attestation.aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` of length `len(committee)`, where the bit of the index of the validator in the `committee` is set to `0b1`. +- Let `attestation.aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT]` of length `len(committee)`, where the bit of the index of the validator in the `committee` is set to `0b1`. - Let `attestation.committee_bits` be a `Bitvector[MAX_COMMITTEES_PER_SLOT]`, where the bit at the index associated with the validator's committee is set to `0b1`. *Note*: Calling `get_attesting_indices(state, attestation)` should return a list of length equal to 1, containing `validator_index`. @@ -64,6 +64,6 @@ def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attesta #### Construct aggregate - Set `attestation_data.index = 0`. -- Let `aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` of length `len(committee)`, where each bit set from each individual attestation is set to `0b1`. +- Let `aggregation_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT]` of length `len(committee)`, where each bit set from each individual attestation is set to `0b1`. - Set `attestation.committee_bits = committee_bits`, where `committee_bits` has the same value as in each individual attestation.