From 1242368b58b96b01399feba0b80a2e9e23750469 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 19 Mar 2024 08:53:54 +0100 Subject: [PATCH 1/9] Align `seen_ttl` with attestation lifetime https://github.com/ethereum/consensus-specs/pull/3360 effectively extends the valid lifetime of an attestation/aggregate to 2 epochs - this means that an aggregate that was published at the beginning of a slot now is valid per the gossip rules up to 2 epochs later. Then net effect of the above change is that peers are allowed to republish old aggregates and attestations and libp2p will not stop the spread with the settings we recommend - instead the messages will have to be stopped with the "attestation cover rule" or similar, even though they have been observed already. Significant amounts of this kind of spam have been observed on the aggregate channel in particular leading to a 5x increase in aggregate traffic as some clients republish these old messages in spite of the "attestation cover rule" which should have stopped them - this simple change will provide an additional layer of protection against such bugs. --- specs/phase0/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index a34b34233..8c25771a0 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -245,7 +245,7 @@ The following gossipsub [parameters](https://github.com/libp2p/specs/blob/master - `fanout_ttl` (ttl for fanout maps for topics we are not subscribed to but have published to, seconds): 60 - `mcache_len` (number of windows to retain full messages in cache for `IWANT` responses): 6 - `mcache_gossip` (number of windows to gossip about): 3 -- `seen_ttl` (number of heartbeat intervals to retain message IDs): 550 +- `seen_ttl` (expiry time for cache of seen message ids, seconds): SECONDS_PER_SLOT * SLOTS_PER_EPOCH * 2 *Note*: Gossipsub v1.1 introduces a number of [additional parameters](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#overview-of-new-parameters) From ec633e8871b3d3fad17413ed85c8444f8b651ad2 Mon Sep 17 00:00:00 2001 From: Mehdi AOUADI Date: Wed, 20 Mar 2024 16:31:46 +0100 Subject: [PATCH 2/9] clarify network aggregation vs onchain aggregation --- specs/_features/eip7549/validator.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/specs/_features/eip7549/validator.md b/specs/_features/eip7549/validator.md index 6ae84aca6..1e260deec 100644 --- a/specs/_features/eip7549/validator.md +++ b/specs/_features/eip7549/validator.md @@ -26,7 +26,28 @@ ##### Attestations -Attestations received from aggregators with disjoint `committee_bits` sets and equal `AttestationData` SHOULD be consolidated into a single `Attestation` object. +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`: + +```python +def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attestation: + + 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] + signature = bls.Aggregate([a.signature for a in aggregates]) + + committee_indices = [get_committee_indices(a.committee_bits)[0] 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) + + return Attestation(aggregation_bits=aggregation_bits, + data=data, + committee_bits=committee_bits, + signature=signature) +``` ### Attesting From 2014edbbaa3aa9e8c5b16b897e04b2fffc2679e8 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Fri, 22 Mar 2024 13:25:03 +0900 Subject: [PATCH 3/9] Update validator.md --- specs/_features/eip7549/validator.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/specs/_features/eip7549/validator.md b/specs/_features/eip7549/validator.md index 1e260deec..7278a1ebf 100644 --- a/specs/_features/eip7549/validator.md +++ b/specs/_features/eip7549/validator.md @@ -32,21 +32,17 @@ The proposer should run the following function to construct an on chain final ag ```python def compute_on_chain_aggregate(network_aggregates: List[Attestation]) -> Attestation: - 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] signature = bls.Aggregate([a.signature for a in aggregates]) - + committee_indices = [get_committee_indices(a.committee_bits)[0] 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) - return Attestation(aggregation_bits=aggregation_bits, - data=data, - committee_bits=committee_bits, - signature=signature) + return Attestation(aggregation_bits, data, committee_bits, signature) ``` ### Attesting From 702ac2885809cb1e772818591c6a5015def5c0e6 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 25 Mar 2024 16:19:11 +0600 Subject: [PATCH 4/9] 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 a2fbafb86e8f4d6be6330d856febadf6f9f680f9 Mon Sep 17 00:00:00 2001 From: parithosh Date: Mon, 25 Mar 2024 12:15:53 +0100 Subject: [PATCH 5/9] add electra configs --- configs/mainnet.yaml | 9 ++++++--- configs/minimal.yaml | 11 +++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 317daa1a4..82f98f819 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -50,14 +50,17 @@ CAPELLA_FORK_EPOCH: 194048 # April 12, 2023, 10:27:35pm UTC # Deneb DENEB_FORK_VERSION: 0x04000000 DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC +# Electra +ELECTRA_FORK_VERSION: 0x05000001 +ELECTRA_FORK_EPOCH: 18446744073709551615 # EIP6110 -EIP6110_FORK_VERSION: 0x05000000 # temporary stub +EIP6110_FORK_VERSION: 0x06000000 # temporary stub EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 -EIP7002_FORK_VERSION: 0x05000000 # temporary stub +EIP7002_FORK_VERSION: 0x07000000 # temporary stub EIP7002_FORK_EPOCH: 18446744073709551615 # WHISK -WHISK_FORK_VERSION: 0x06000000 # temporary stub +WHISK_FORK_VERSION: 0x08000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 6b2da84fd..4406935e0 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -46,17 +46,20 @@ BELLATRIX_FORK_EPOCH: 18446744073709551615 # Capella CAPELLA_FORK_VERSION: 0x03000001 CAPELLA_FORK_EPOCH: 18446744073709551615 -# DENEB +# Deneb DENEB_FORK_VERSION: 0x04000001 DENEB_FORK_EPOCH: 18446744073709551615 +# Electra +ELECTRA_FORK_VERSION: 0x05000001 +ELECTRA_FORK_EPOCH: 18446744073709551615 # EIP6110 -EIP6110_FORK_VERSION: 0x05000001 +EIP6110_FORK_VERSION: 0x06000001 EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 -EIP7002_FORK_VERSION: 0x05000001 +EIP7002_FORK_VERSION: 0x07000001 EIP7002_FORK_EPOCH: 18446744073709551615 # WHISK -WHISK_FORK_VERSION: 0x06000001 +WHISK_FORK_VERSION: 0x08000001 WHISK_FORK_EPOCH: 18446744073709551615 From 45803e6b83e128eb2c483d13cb31f9d9f6f7d623 Mon Sep 17 00:00:00 2001 From: parithosh Date: Mon, 25 Mar 2024 12:19:31 +0100 Subject: [PATCH 6/9] fix fork version --- configs/mainnet.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 82f98f819..6afc82e95 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -51,7 +51,7 @@ CAPELLA_FORK_EPOCH: 194048 # April 12, 2023, 10:27:35pm UTC DENEB_FORK_VERSION: 0x04000000 DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC # Electra -ELECTRA_FORK_VERSION: 0x05000001 +ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x06000000 # temporary stub From bb8ba9c0456a7080917cd976210fa7c355c709b2 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 25 Mar 2024 19:20:58 +0600 Subject: [PATCH 7/9] 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. From 88a35a1de1e77f7ca7b1f2915bc211d54783bd69 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 26 Mar 2024 13:18:40 +0800 Subject: [PATCH 8/9] update the spec files too --- specs/_features/eip6110/fork.md | 2 +- specs/_features/eip7002/fork.md | 2 +- specs/_features/whisk/fork.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/_features/eip6110/fork.md b/specs/_features/eip6110/fork.md index 6b5ab0431..8bb8e2a67 100644 --- a/specs/_features/eip6110/fork.md +++ b/specs/_features/eip6110/fork.md @@ -28,7 +28,7 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `EIP6110_FORK_VERSION` | `Version('0x05000000')` | +| `EIP6110_FORK_VERSION` | `Version('0x06000000')` | | `EIP6110_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | ## Helper functions diff --git a/specs/_features/eip7002/fork.md b/specs/_features/eip7002/fork.md index 87008de77..8f095389d 100644 --- a/specs/_features/eip7002/fork.md +++ b/specs/_features/eip7002/fork.md @@ -28,7 +28,7 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `EIP7002_FORK_VERSION` | `Version('0x05000000')` | +| `EIP7002_FORK_VERSION` | `Version('0x07000000')` | | `EIP7002_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | ## Helper functions diff --git a/specs/_features/whisk/fork.md b/specs/_features/whisk/fork.md index ef3eb0846..300d19129 100644 --- a/specs/_features/whisk/fork.md +++ b/specs/_features/whisk/fork.md @@ -41,7 +41,7 @@ Warning: this configuration is not definitive. | Name | Value | | -------------------- | ----------------------- | -| `WHISK_FORK_VERSION` | `Version('0x05000000')` | +| `WHISK_FORK_VERSION` | `Version('0x08000000')` | | `WHISK_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | ## Fork to Whisk From 7d595a7091e20f8000a9372f47e4c23122b5ea62 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 28 Mar 2024 07:48:52 -0600 Subject: [PATCH 9/9] Update single_merkle_proof.md Typo in file name suggesting the wrong format --- tests/formats/light_client/single_merkle_proof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/formats/light_client/single_merkle_proof.md b/tests/formats/light_client/single_merkle_proof.md index d2137605e..0cb4cd0d0 100644 --- a/tests/formats/light_client/single_merkle_proof.md +++ b/tests/formats/light_client/single_merkle_proof.md @@ -7,7 +7,7 @@ generation and verification of merkle proofs based on static data. Tests for each individual SSZ type are grouped into a `suite` indicating the SSZ type name. -### `object.yaml` +### `object.ssz_snappy` A SSZ-snappy encoded object from which other data is generated. The SSZ type can be determined from the test `suite` name.