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

[WIP] move attestation index outside signed message #2

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
70ce4f2
Remove extra tick
hwwhww Nov 14, 2023
3d853b0
Add `assert time >= store.time` to `on_tick`
hwwhww Nov 16, 2023
1028093
Merge pull request #3548 from ethereum/fix-fc-script
hwwhww Nov 29, 2023
6fb9b0a
Revert the spec. Only handle it in tests
hwwhww Nov 29, 2023
a8d0268
Merge branch 'dev' into on-tick-precondition
hwwhww Nov 30, 2023
581a64b
cleanup leftover
hwwhww Nov 30, 2023
8fa1f8e
Merge pull request #3550 from ethereum/on-tick-precondition
djrtwo Nov 30, 2023
e664d40
Specify RPC byRoot blocks-sidecars elegibility
tbenr Nov 16, 2023
c46c4ec
fix typo
tbenr Nov 16, 2023
6bbdeb8
Update specs/phase0/p2p-interface.md
tbenr Nov 17, 2023
ccf9e34
Update specs/deneb/p2p-interface.md
tbenr Nov 17, 2023
e2ca4b3
add failed on_block condition
tbenr Nov 22, 2023
d749a49
rephrase
tbenr Nov 22, 2023
4c5e5c8
Update specs/phase0/p2p-interface.md
tbenr Nov 29, 2023
ccca449
apply suggestion
tbenr Nov 29, 2023
88b1818
Update specs/deneb/p2p-interface.md
tbenr Nov 30, 2023
b525e9e
Update specs/deneb/p2p-interface.md
tbenr Nov 30, 2023
662c6eb
remove the last consider
tbenr Nov 30, 2023
bdac932
from on_block to state_transition
tbenr Nov 30, 2023
6a460ae
Add randomized block cases
hwwhww Nov 30, 2023
c661e20
simplify and add a new rule
tbenr Nov 30, 2023
113c58f
Merge pull request #3555 from ethereum/random-blob_kzg_commitment_mer…
djrtwo Nov 30, 2023
dad09f6
Update specs/phase0/p2p-interface.md
tbenr Dec 1, 2023
eed7a66
Update specs/deneb/p2p-interface.md
tbenr Dec 1, 2023
cf39eed
Update specs/deneb/p2p-interface.md
tbenr Dec 1, 2023
ba09761
remove gossip failure rules
tbenr Dec 1, 2023
c43173e
Move `blob_sidecar_{subnet_id}` to `Blob subnets` section
hwwhww Dec 1, 2023
d343b6f
Apply suggestions from code review
djrtwo Dec 4, 2023
06fe616
Merge pull request #3551 from tbenr/specify_rpc_by_root_elegibility
hwwhww Dec 4, 2023
a558f19
bump version to v1.4.0-beta.5
hwwhww Dec 4, 2023
4420c64
Merge pull request #3558 from ethereum/bump-version
djrtwo Dec 4, 2023
b2f2102
Merge pull request #3556 from ethereum/blob-subnets
djrtwo Dec 4, 2023
68df5cc
move attestation index outside signed message
dapplion Oct 31, 2023
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
4 changes: 2 additions & 2 deletions pysetup/spec_builders/phase0.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ def wrapper(*args, **kw): # type: ignore
_get_attesting_indices = get_attesting_indices
get_attesting_indices = cache_this(
lambda state, data, bits: (
lambda state, attestation: (
state.randao_mixes.hash_tree_root(),
state.validators.hash_tree_root(), data.hash_tree_root(), bits.hash_tree_root()
state.validators.hash_tree_root(), attestation.hash_tree_root()
),
_get_attesting_indices, lru_size=SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT * 3)'''
4 changes: 2 additions & 2 deletions specs/_features/custody_game/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ def process_chunk_challenge(state: BeaconState, challenge: CustodyChunkChallenge
# Verify responder is slashable
assert is_slashable_validator(responder, get_current_epoch(state))
# Verify the responder participated in the attestation
attesters = get_attesting_indices(state, challenge.attestation.data, challenge.attestation.aggregation_bits)
attesters = get_attesting_indices(state, challenge)
assert challenge.responder_index in attesters
# Verify shard transition is correctly given
assert hash_tree_root(challenge.shard_transition) == challenge.attestation.data.shard_transition_root
Expand Down Expand Up @@ -594,7 +594,7 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed
assert len(custody_slashing.data) == shard_transition.shard_block_lengths[custody_slashing.data_index]
assert hash_tree_root(custody_slashing.data) == shard_transition.shard_data_roots[custody_slashing.data_index]
# Verify existence and participation of claimed malefactor
attesters = get_attesting_indices(state, attestation.data, attestation.aggregation_bits)
attesters = get_attesting_indices(state, attestation)
assert custody_slashing.malefactor_index in attesters

# Verify the malefactor custody key
Expand Down
64 changes: 64 additions & 0 deletions specs/_features/eip7549/beacon-chain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# EIP-7549 -- The Beacon Chain

## 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 -->

- [Introduction](#introduction)
- [Containers](#containers)
- [Extended containers](#extended-containers)
- [AttestationData](#attestationdata)
- [Attestation](#attestation)
- [Helper functions](#helper-functions)
- [Beacon state accessors](#beacon-state-accessors)
- [Modified `get_attestation_index`](#modified-get_attestation_index)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->

## Introduction

This is the beacon chain specification to move the attestation committee index outside of the signed message. For motivation, refer to [EIP-7549](https://github.com/ethereum/EIPs/pull/7944).

*Note:* This specification is built upon [Deneb](../../deneb/beacon_chain.md) and is under active development.

## 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
```

#### Attestation

```python
class Attestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData
index: CommitteeIndex # [New in EIP7549]
signature: BLSSignature
```

## Helper functions

### Beacon state accessors

#### Modified `get_attestation_index`

```python
def get_attestation_index(attestation: Attestation) -> CommitteeIndex:
return attestation.index
```

2 changes: 1 addition & 1 deletion specs/altair/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
epoch_participation = state.previous_epoch_participation

proposer_reward_numerator = 0
for index in get_attesting_indices(state, data, attestation.aggregation_bits):
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)
Expand Down
2 changes: 1 addition & 1 deletion specs/altair/fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def translate_participation(state: BeaconState, pending_attestations: Sequence[p

# Apply flags to all attesting validators
epoch_participation = state.previous_epoch_participation
for index in get_attesting_indices(state, data, attestation.aggregation_bits):
for index in get_attesting_indices(state, attestation):
for flag_index in participation_flag_indices:
epoch_participation[index] = add_flag(epoch_participation[index], flag_index)

Expand Down
7 changes: 4 additions & 3 deletions specs/deneb/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,13 @@ 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 data.index < get_committee_count_per_slot(state, data.target.epoch)
assert index < get_committee_count_per_slot(state, data.target.epoch)

committee = get_beacon_committee(state, data.slot, data.index)
committee = get_beacon_committee(state, data.slot, index)
assert len(attestation.aggregation_bits) == len(committee)

# Participation flag indices
Expand All @@ -337,7 +338,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
epoch_participation = state.previous_epoch_participation

proposer_reward_numerator = 0
for index in get_attesting_indices(state, data, attestation.aggregation_bits):
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)
Expand Down
49 changes: 29 additions & 20 deletions specs/deneb/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ The specification of these changes continues in the same format as the network s
- [Topics and messages](#topics-and-messages)
- [Global topics](#global-topics)
- [`beacon_block`](#beacon_block)
- [`blob_sidecar_{subnet_id}`](#blob_sidecar_subnet_id)
- [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof)
- [Blob subnets](#blob-subnets)
- [`blob_sidecar_{subnet_id}`](#blob_sidecar_subnet_id)
- [Attestation subnets](#attestation-subnets)
- [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id)
- [Transitioning the gossip](#transitioning-the-gossip)
Expand Down Expand Up @@ -133,8 +134,6 @@ The new topics along with the type of the `data` field of a gossipsub message ar

##### Global topics

Deneb introduces new global topics for blob sidecars.

###### `beacon_block`

The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in Deneb.
Expand All @@ -146,6 +145,25 @@ New validation:
- _[REJECT]_ The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer --
i.e. validate that `len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK`

###### `beacon_aggregate_and_proof`

*[Modified in Deneb:EIP7045]*

The following validation is removed:
* _[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`
(a client MAY queue future aggregates for processing at the appropriate slot).

The following validations are added in its place:
* _[IGNORE]_ `aggregate.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) --
i.e. `aggregate.data.slot <= current_slot`
(a client MAY queue future aggregates for processing at the appropriate slot).
* _[IGNORE]_ the epoch of `aggregate.data.slot` is either the current or previous epoch
(with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) --
i.e. `compute_epoch_at_slot(aggregate.data.slot) in (get_previous_epoch(state), get_current_epoch(state))`

##### Blob subnets

###### `blob_sidecar_{subnet_id}`

*[New in Deneb:EIP4844]*
Expand All @@ -169,23 +187,6 @@ The following validations MUST pass before forwarding the `blob_sidecar` on the
- _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `block_header.parent_root`/`block_header.slot`).
If the `proposer_index` cannot immediately be verified against the expected shuffling, the sidecar MAY be queued for later processing while proposers for the block's branch are calculated -- in such a case _do not_ `REJECT`, instead `IGNORE` this message.

###### `beacon_aggregate_and_proof`

*[Modified in Deneb:EIP7045]*

The following validation is removed:
* _[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`
(a client MAY queue future aggregates for processing at the appropriate slot).

The following validations are added in its place:
* _[IGNORE]_ `aggregate.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) --
i.e. `aggregate.data.slot <= current_slot`
(a client MAY queue future aggregates for processing at the appropriate slot).
* _[IGNORE]_ the epoch of `aggregate.data.slot` is either the current or previous epoch
(with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) --
i.e. `compute_epoch_at_slot(aggregate.data.slot) in (get_previous_epoch(state), get_current_epoch(state))`

##### Attestation subnets

###### `beacon_attestation_{subnet_id}`
Expand Down Expand Up @@ -252,6 +253,10 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`:

No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time.

*[Modified in Deneb:EIP4844]*
Clients SHOULD include a block in the response as soon as it passes the gossip validation rules.
Clients SHOULD NOT respond with blocks that fail the beacon chain state transition.

##### BlobSidecarsByRoot v1

**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/`
Expand Down Expand Up @@ -300,6 +305,10 @@ Clients MUST support requesting sidecars since `minimum_request_epoch`, where `m
Clients MUST respond with at least one sidecar, if they have it.
Clients MAY limit the number of blocks and sidecars in the response.

Clients SHOULD include a sidecar in the response as soon as it passes the gossip validation rules.
Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules.
Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition

##### BlobSidecarsByRange v1

**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/`
Expand Down
22 changes: 14 additions & 8 deletions specs/phase0/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
- [`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)
Expand Down Expand Up @@ -1082,7 +1083,7 @@ def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> Ind
"""
Return the indexed attestation corresponding to ``attestation``.
"""
attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bits)
attesting_indices = get_attesting_indices(state, attestation)

return IndexedAttestation(
attesting_indices=sorted(attesting_indices),
Expand All @@ -1094,14 +1095,19 @@ def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> Ind
#### `get_attesting_indices`

```python
def get_attesting_indices(state: BeaconState,
data: AttestationData,
bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]) -> Set[ValidatorIndex]:
def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
"""
Return the set of attesting indices corresponding to ``data`` and ``bits``.
"""
committee = get_beacon_committee(state, data.slot, data.index)
return set(index for i, index in enumerate(committee) if bits[i])
committee = get_beacon_committee(state, attestation.data.slot, get_attestation_index(attestation))
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
Expand Down Expand Up @@ -1339,7 +1345,7 @@ def get_unslashed_attesting_indices(state: BeaconState,
attestations: Sequence[PendingAttestation]) -> Set[ValidatorIndex]:
output = set() # type: Set[ValidatorIndex]
for a in attestations:
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
output = output.union(get_attesting_indices(state, a))
return set(filter(lambda index: not state.validators[index].slashed, output))
```

Expand Down Expand Up @@ -1512,7 +1518,7 @@ def get_inclusion_delay_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequ
for index in get_unslashed_attesting_indices(state, matching_source_attestations):
attestation = min([
a for a in matching_source_attestations
if index in get_attesting_indices(state, a.data, a.aggregation_bits)
if index in get_attesting_indices(state, a)
], key=lambda a: a.inclusion_delay)
rewards[attestation.proposer_index] += get_proposer_reward(state, index)
max_attester_reward = Gwei(get_base_reward(state, index) - get_proposer_reward(state, index))
Expand Down
19 changes: 11 additions & 8 deletions specs/phase0/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ The `beacon_aggregate_and_proof` topic is used to propagate aggregated attestati
to subscribing nodes (typically validators) to be included in future blocks.

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` and `aggregate = aggregate_and_proof.aggregate`)
(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)`)
- _[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`
(a client MAY queue future aggregates for processing at the appropriate slot).
Expand All @@ -364,12 +364,11 @@ The following validations MUST pass before forwarding the `signed_aggregate_and_
(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
with index `aggregate_and_proof.aggregator_index` for the epoch `aggregate.data.target.epoch`.
- _[REJECT]_ The attestation has participants --
that is, `len(get_attesting_indices(state, aggregate.data, aggregate.aggregation_bits)) >= 1`.
- _[REJECT]_ The attestation has participants -- that is, `len(get_attesting_indices(state, aggregate)) >= 1`.
- _[REJECT]_ `aggregate_and_proof.selection_proof` selects the validator as an aggregator for the slot --
i.e. `is_aggregator(state, aggregate.data.slot, aggregate.data.index, aggregate_and_proof.selection_proof)` returns `True`.
i.e. `is_aggregator(state, aggregate.data.slot, index, aggregate_and_proof.selection_proof)` returns `True`.
- _[REJECT]_ The aggregator's validator index is within the committee --
i.e. `aggregate_and_proof.aggregator_index in get_beacon_committee(state, aggregate.data.slot, aggregate.data.index)`.
i.e. `aggregate_and_proof.aggregator_index in get_beacon_committee(state, aggregate.data.slot, index)`.
- _[REJECT]_ The `aggregate_and_proof.selection_proof` is a valid signature
of the `aggregate.data.slot` by the validator with index `aggregate_and_proof.aggregator_index`.
- _[REJECT]_ The aggregator signature, `signed_aggregate_and_proof.signature`, is valid.
Expand Down Expand Up @@ -425,9 +424,10 @@ The `beacon_attestation_{subnet_id}` topics are used to propagate unaggregated a
to the subnet `subnet_id` (typically beacon and persistent committees) to be aggregated before being gossiped to `beacon_aggregate_and_proof`.

The following validations MUST pass before forwarding the `attestation` on the subnet.
- _[REJECT]_ The committee index is within the expected range -- i.e. `data.index < get_committee_count_per_slot(state, data.target.epoch)`.
(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, data.target.epoch)`.
- _[REJECT]_ The attestation is for the correct subnet --
i.e. `compute_subnet_for_attestation(committees_per_slot, attestation.data.slot, attestation.data.index) == subnet_id`,
i.e. `compute_subnet_for_attestation(committees_per_slot, attestation.data.slot, index) == subnet_id`,
where `committees_per_slot = get_committee_count_per_slot(state, attestation.data.target.epoch)`,
which may be pre-computed along with the committee information for the signature check.
- _[IGNORE]_ `attestation.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots
Expand All @@ -439,7 +439,7 @@ The following validations MUST pass before forwarding the `attestation` on the s
- _[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).
- _[REJECT]_ The number of aggregation bits matches the committee size -- i.e.
`len(attestation.aggregation_bits) == len(get_beacon_committee(state, data.slot, data.index))`.
`len(attestation.aggregation_bits) == len(get_beacon_committee(state, 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.
Expand Down Expand Up @@ -856,6 +856,9 @@ Clients MUST support requesting blocks since the latest finalized epoch.
Clients MUST respond with at least one block, if they have it.
Clients MAY limit the number of blocks in the response.

Clients MAY include a block in the response as soon as it passes the gossip validation rules.
Clients SHOULD NOT respond with blocks that fail the beacon chain state transition.

`/eth2/beacon_chain/req/beacon_blocks_by_root/1/` is deprecated. Clients MAY respond with an empty list during the deprecation transition period.

##### Ping
Expand Down
2 changes: 1 addition & 1 deletion specs/phase0/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ Set `attestation.data = attestation_data` where `attestation_data` is the `Attes

- 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`.

*Note*: Calling `get_attesting_indices(state, attestation.data, attestation.aggregation_bits)` should return a list of length equal to 1, containing `validator_index`.
*Note*: Calling `get_attesting_indices(state, attestation)` should return a list of length equal to 1, containing `validator_index`.

##### Aggregate signature

Expand Down
2 changes: 1 addition & 1 deletion tests/core/pyspec/eth2spec/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.0-beta.4
1.4.0-beta.5
Loading