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

Separate type for aggregated committee attestation #4005

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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
11 changes: 11 additions & 0 deletions specs/electra/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [`WithdrawalRequest`](#withdrawalrequest)
- [`ConsolidationRequest`](#consolidationrequest)
- [`SingleAttestation`](#singleattestation)
- [`CommitteeAttestation`](#committeeattestation)
- [`ExecutionRequests`](#executionrequests)
- [Modified Containers](#modified-containers)
- [`AttesterSlashing`](#attesterslashing)
Expand Down Expand Up @@ -281,6 +282,16 @@ class SingleAttestation(Container):
signature: BLSSignature
```

#### `CommitteeAttestation`

```python
class CommitteeAttestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData
committee_index: CommitteeIndex
signature: BLSSignature
```

#### `ExecutionRequests`

*Note*: This container holds requests from the execution layer that are received in [
Expand Down
3 changes: 1 addition & 2 deletions specs/electra/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ The derivation of the `message-id` remains stable.
##### `beacon_aggregate_and_proof`

The following convenience variables are re-defined
- `index = get_committee_indices(aggregate.committee_bits)[0]`
- `index = aggregate.committee_index`

The following validations are added:
* [REJECT] `len(committee_indices) == 1`, where `committee_indices = get_committee_indices(aggregate)`.
* [REJECT] `aggregate.data.index == 0`

#### Attestation subnets
Expand Down
43 changes: 35 additions & 8 deletions specs/electra/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- [Construct attestation](#construct-attestation)
- [Attestation aggregation](#attestation-aggregation)
- [Construct aggregate](#construct-aggregate)
- [Broadcast aggregate](#broadcast-aggregate)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
Expand Down Expand Up @@ -66,7 +67,7 @@ class GetPayloadResponse(object):
```python
class AggregateAndProof(Container):
aggregator_index: ValidatorIndex
aggregate: Attestation # [Modified in Electra:EIP7549]
aggregate: CommitteeAttestation # [Modified in Electra:EIP7549]
selection_proof: BLSSignature
```

Expand Down Expand Up @@ -109,22 +110,22 @@ Changed the max attester slashings size to `MAX_ATTESTER_SLASHINGS_ELECTRA`.
Changed the max attestations size to `MAX_ATTESTATIONS_ELECTRA`.

The network attestation aggregates contain only the assigned committee attestations.
Attestation aggregates received by the block proposer from the committee aggregators with disjoint `committee_bits` sets and equal `AttestationData` SHOULD be consolidated into a single `Attestation` object.
The proposer should run the following function to construct an on chain final aggregate form a list of network aggregates with equal `AttestationData`:
Committee attestations received by the block proposer from the committee aggregators with different `committee_index` sets and equal `AttestationData` SHOULD be consolidated into a single `Attestation` object.
The proposer should run the following function to construct an on chain final aggregate form a list of committee attestations with equal `AttestationData`:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
The proposer should run the following function to construct an on chain final aggregate form a list of committee attestations with equal `AttestationData`:
The proposer should run the following function to construct an on-chain final aggregate from a list of committee attestations with equal `AttestationData`:


```python
def compute_on_chain_aggregate(network_aggregates: Sequence[Attestation]) -> Attestation:
aggregates = sorted(network_aggregates, key=lambda a: get_committee_indices(a.committee_bits)[0])
def compute_on_chain_aggregate(committee_attestations: Sequence[CommitteeAttestation]) -> Attestation:
attestations = sorted(committee_attestations, key=lambda a: a.committee_index)

data = aggregates[0].data
data = attestations[0].data
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]
committee_indices = [a.committee_index for a in aggregates]
committee_flags = [(index in committee_indices) for index in range(0, MAX_COMMITTEES_PER_SLOT)]
committee_bits = Bitvector[MAX_COMMITTEES_PER_SLOT](committee_flags)

Expand Down Expand Up @@ -220,4 +221,30 @@ with updated field assignments:

- Set `attestation_data.index = 0`.
- 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 bit set corresponding to `committee_index` in each individual attestation.
- Set `attestation.committee_index = committee_index`, where `committee_index` is the `committee_index` in each individual attestation.
Copy link
Member

Choose a reason for hiding this comment

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

Making it the same as in "Construct attestation" would be easier. Reordering this to be the second one as in "Construct attestation" would even be better.

Suggested change
- Set `attestation.committee_index = committee_index`, where `committee_index` is the `committee_index` in each individual attestation.
- Set `attestation.committee_index` to the index associated with the validator's committee.


#### Aggregate signature

Set `aggregate_attestation.signature = aggregate_signature` where `aggregate_signature` is obtained from:

```python
def get_aggregate_signature(attestations: Sequence[CommitteeAttestation]) -> BLSSignature:
signatures = [attestation.signature for attestation in attestations]
return bls.Aggregate(signatures)
```

### Broadcast aggregate

`get_aggregate_and_proof` is modified to accept `CommitteeAttestation` for `aggregate`.

```python
def get_aggregate_and_proof(state: BeaconState,
aggregator_index: ValidatorIndex,
committee_attestation: CommitteeAttestation,
privkey: int) -> AggregateAndProof:
return AggregateAndProof(
aggregator_index=aggregator_index,
aggregate=committee_attestation,
selection_proof=get_slot_signature(state, aggregate.data.slot, privkey),
)
```
Comment on lines +225 to +250
Copy link
Member

Choose a reason for hiding this comment

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

I think these two sections are trivial and wordy and unrelated to the change, right? I would say they are not needed.

Suggested change
#### Aggregate signature
Set `aggregate_attestation.signature = aggregate_signature` where `aggregate_signature` is obtained from:
```python
def get_aggregate_signature(attestations: Sequence[CommitteeAttestation]) -> BLSSignature:
signatures = [attestation.signature for attestation in attestations]
return bls.Aggregate(signatures)
```
### Broadcast aggregate
`get_aggregate_and_proof` is modified to accept `CommitteeAttestation` for `aggregate`.
```python
def get_aggregate_and_proof(state: BeaconState,
aggregator_index: ValidatorIndex,
committee_attestation: CommitteeAttestation,
privkey: int) -> AggregateAndProof:
return AggregateAndProof(
aggregator_index=aggregator_index,
aggregate=committee_attestation,
selection_proof=get_slot_signature(state, aggregate.data.slot, privkey),
)
```