Update spec with @mkalinin suggestions

This commit is contained in:
dapplion 2024-03-05 20:46:45 +08:00
parent accee2b8be
commit 38f269ca12
6 changed files with 225 additions and 41 deletions

View File

@ -7,13 +7,19 @@
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Introduction](#introduction)
- [Preset](#preset)
- [Containers](#containers)
- [Extended containers](#extended-containers)
- [AttestationData](#attestationdata)
- [Modified containers](#modified-containers)
- [Attestation](#attestation)
- [IndexedAttestation](#indexedattestation)
- [Helper functions](#helper-functions)
- [Misc](#misc)
- [`get_committee_indices`](#get_committee_indices)
- [Beacon state accessors](#beacon-state-accessors)
- [Modified `get_attestation_index`](#modified-get_attestation_index)
- [New `get_committee_attesters`](#new-get_committee_attesters)
- [Modified `get_attesting_indices`](#modified-get_attesting_indices)
- [Block processing](#block-processing)
- [Modified `process_attestation`](#modified-process_attestation)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
@ -24,41 +30,117 @@ This is the beacon chain specification to move the attestation committee index o
*Note:* This specification is built upon [Deneb](../../deneb/beacon_chain.md) and is under active development.
## Preset
| Name | Value | Description |
| - | - | - |
| `MAX_ATTESTER_SLASHINGS` | `2**0` (= 1) |
| `MAX_ATTESTATIONS` | `2**3` (= 8) |
## Containers
### Extended containers
#### AttestationData
```python
class AttestationData(Container):
slot: Slot
# index: CommitteeIndex # [Modified in EIP7549]
# LMD GHOST vote
beacon_block_root: Root
# FFG vote
source: Checkpoint
target: Checkpoint
```
### Modified containers
#### Attestation
```python
class Attestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
aggregation_bits: List[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
```
#### IndexedAttestation
```python
class IndexedAttestation(Container):
attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] # [Modified in EIP7549]
data: AttestationData
index: CommitteeIndex # [New in EIP7549]
signature: BLSSignature
```
## Helper functions
### Beacon state accessors
### Misc
#### Modified `get_attestation_index`
#### `get_committee_indices`
```python
def get_attestation_index(attestation: Attestation) -> CommitteeIndex:
return attestation.index
def get_committee_indices(commitee_bits: Bitvector) -> List[CommitteeIndex]:
return [CommitteeIndex(index) for bit, index in enumerate(commitee_bits) if bit]
```
### Beacon state accessors
#### New `get_committee_attesters`
```python
def get_committee_attesters(state: BeaconState, attesting_bits: Bitlist, index: CommitteeIndex) -> Set[ValidatorIndex]:
committee = get_beacon_committee(state, data.slot, index)
return set(index for i, index in enumerate(committee) if attesting_bits[i])
```
#### Modified `get_attesting_indices`
```python
def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
"""
Return the set of attesting indices corresponding to ``aggregation_bits`` and ``committee_bits``.
"""
output = set()
committee_indices = get_committee_indices(attestation.committee_bits)
for index in committee_indices:
attesting_bits = attestation.attesting_bits[index]
committee_attesters = get_committee_attesters(state, attesting_bits, index)
output = output.union(committee_attesters)
return output
```
### Block processing
#### Modified `process_attestation`
```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
data = attestation.data
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.target.epoch == compute_epoch_at_slot(data.slot)
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot
# [Modified in EIP7549]
assert data.index == 0
committee_indices = get_committee_indices(attestation.committee_bits)
assert len(committee_indices) > 0
assert len(committee_indices) == len(attestation.aggregation_bits)
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)
# Participation flag indices
participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot)
# Verify signature
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
# Update epoch participation flags
if data.target.epoch == get_current_epoch(state):
epoch_participation = state.current_epoch_participation
else:
epoch_participation = state.previous_epoch_participation
proposer_reward_numerator = 0
for index in get_attesting_indices(state, attestation):
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):
epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
proposer_reward_numerator += get_base_reward(state, index) * weight
# Reward proposer
proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
```

View File

@ -0,0 +1,54 @@
# EIP-7549 -- Networking
This document contains the consensus-layer networking specification for EIP-7549.
The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite.
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Modifications in EIP-7549](#modifications-in-eip-7549)
- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub)
- [Topics and messages](#topics-and-messages)
- [Global topics](#global-topics)
- [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof)
- [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Modifications in EIP-7549
### The gossip domain: gossipsub
#### Topics and messages
The `beacon_aggregate_and_proof` and `beacon_attestation_{subnet_id}` topics are modified to support the gossip of a new attestation type.
##### Global topics
###### `beacon_aggregate_and_proof`
*[Modified in EIP7549]*
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] `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] `attestation.data.index == 0`

View File

@ -0,0 +1,49 @@
# Deneb -- Honest Validator
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Modifications in EIP-7549](#modifications-in-eip-7549)
- [Block proposal](#block-proposal)
- [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody)
- [Attestations](#attestations)
- [Attesting](#attesting)
- [Construct attestation](#construct-attestation)
- [Attestation aggregation](#attestation-aggregation)
- [Construct aggregate](#construct-aggregate)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Modifications in EIP-7549
### Block proposal
#### Constructing the `BeaconBlockBody`
##### Attestations
Attestations received from aggregators with disjoint `committee_bits` sets and equal `AttestationData` SHOULD be consolidated into a single `Attestation` object.
### Attesting
#### 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
*Note*: Calling `get_attesting_indices(state, attestation)` should return a list of length equal to 1, containing `validator_index`.
### Attestation aggregation
#### 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`.
- Set `attestation.aggregation_bits = [aggregation_bits]`, a list of length 1

View File

@ -316,13 +316,12 @@ def verify_and_notify_new_payload(self: ExecutionEngine,
```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
data = attestation.data
index = get_attestation_index(attestation)
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.target.epoch == compute_epoch_at_slot(data.slot)
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # [Modified in Deneb:EIP7045]
assert index < get_committee_count_per_slot(state, data.target.epoch)
assert data.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, data.index)
assert len(attestation.aggregation_bits) == len(committee)
# Participation flag indices

View File

@ -100,7 +100,6 @@
- [`get_domain`](#get_domain)
- [`get_indexed_attestation`](#get_indexed_attestation)
- [`get_attesting_indices`](#get_attesting_indices)
- [`get_attestation_index`](#get_attestation_index)
- [Beacon state mutators](#beacon-state-mutators)
- [`increase_balance`](#increase_balance)
- [`decrease_balance`](#decrease_balance)
@ -1103,17 +1102,10 @@ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[V
"""
Return the set of attesting indices corresponding to ``data`` and ``bits``.
"""
committee = get_beacon_committee(state, attestation.data.slot, get_attestation_index(attestation))
committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
return set(index for i, index in enumerate(committee) if attestation.aggregation_bits[i])
```
#### `get_attestation_index`
```python
def get_attestation_index(attestation: Attestation) -> CommitteeIndex:
return attestation.data.index
```
### Beacon state mutators
#### `increase_balance`

View File

@ -353,8 +353,13 @@ The following validations MUST pass before forwarding the `signed_beacon_block`
The `beacon_aggregate_and_proof` topic is used to propagate aggregated attestations (as `SignedAggregateAndProof`s)
to subscribing nodes (typically validators) to be included in future blocks.
We define the following variables for convenience:
- `aggregate_and_proof = signed_aggregate_and_proof.message`
- `aggregate = aggregate_and_proof.aggregate`
- `index = aggregate.index`
- `aggregation_bits = attestation.aggregation_bits`
The following validations MUST pass before forwarding the `signed_aggregate_and_proof` on the network.
(We define the following for convenience -- `aggregate_and_proof = signed_aggregate_and_proof.message`, `aggregate = aggregate_and_proof.aggregate` and `index = get_attestation_index(aggregate)`)
- _[REJECT]_ The committee index is within the expected range -- i.e. `index < get_committee_count_per_slot(state, aggregate.data.target.epoch)`.
- _[IGNORE]_ `aggregate.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) --
i.e. `aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot`
@ -362,9 +367,9 @@ 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(aggregate.aggregation_bits) == len(get_beacon_committee(state, aggregate.data.slot, aggregate.data.index))`.
`len(aggregation_bits) == len(get_beacon_committee(state, aggregate.data.slot, aggregate.data.index))`.
- _[REJECT]_ The aggregate attestation has participants --
that is, `len(get_attesting_indices(state, aggregate.data, aggregate.aggregation_bits)) >= 1`.
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.
(via aggregate gossip, within a verified block, or through the creation of an equivalent aggregate locally).
- _[IGNORE]_ The `aggregate` is the first valid aggregate received for the aggregator
@ -430,8 +435,11 @@ Attestation subnets are used to propagate unaggregated attestations to subsectio
The `beacon_attestation_{subnet_id}` topics are used to propagate unaggregated attestations
to the subnet `subnet_id` (typically beacon and persistent committees) to be aggregated before being gossiped to `beacon_aggregate_and_proof`.
We define the following variables for convenience:
- `index = attestation.index`
- `aggregation_bits = attestation.aggregation_bits`
The following validations MUST pass before forwarding the `attestation` on the subnet.
(We define the following for convenience -- `index = get_attestation_index(attestation)`)
- _[REJECT]_ The committee index is within the expected range -- i.e. `index < get_committee_count_per_slot(state, attestation.data.target.epoch)`.
- _[REJECT]_ The attestation is for the correct subnet --
i.e. `compute_subnet_for_attestation(committees_per_slot, attestation.data.slot, index) == subnet_id`,
@ -444,9 +452,9 @@ The following validations MUST pass before forwarding the `attestation` on the s
- _[REJECT]_ The attestation's epoch matches its target -- i.e. `attestation.data.target.epoch ==
compute_epoch_at_slot(attestation.data.slot)`
- _[REJECT]_ The attestation is unaggregated --
that is, it has exactly one participating validator (`len([bit for bit in attestation.aggregation_bits if bit]) == 1`, i.e. exactly 1 bit is set).
that is, it has exactly one participating validator (`len([bit for bit in aggregation_bits if bit]) == 1`, i.e. exactly 1 bit is set).
- _[REJECT]_ The number of aggregation bits matches the committee size -- i.e.
`len(attestation.aggregation_bits) == len(get_beacon_committee(state, attestation.data.slot, index))`.
`len(aggregation_bits) == len(get_beacon_committee(state, attestation.data.slot, index))`.
- _[IGNORE]_ There has been no other valid attestation seen on an attestation subnet
that has an identical `attestation.data.target.epoch` and participating validator index.
- _[REJECT]_ The signature of `attestation` is valid.