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

Remove custody_bits and AttestationDataAndCustodyBit #1462

Closed
wants to merge 4 commits into from
Closed
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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ The following are the broad design goals for Ethereum 2.0:

## For spec contributors


Documentation on the different components used during spec writing can be found here:
* [YAML Test Generators](test_generators/README.md)
* [Executable Python Spec, with Py-tests](test_libs/pyspec/README.md)
Expand Down
3 changes: 1 addition & 2 deletions scripts/build_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@
signing_root,
)
from eth2spec.utils.ssz.ssz_typing import (
bit, boolean, Container, List, Vector, uint64,
boolean, Container, List, Vector, uint64,
Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
)
from eth2spec.utils.bls import (
bls_aggregate_signatures,
bls_aggregate_pubkeys,
bls_verify,
bls_verify_multiple,
bls_sign,
)

Expand Down
56 changes: 11 additions & 45 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
- [`Checkpoint`](#checkpoint)
- [`Validator`](#validator)
- [`AttestationData`](#attestationdata)
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
- [`IndexedAttestation`](#indexedattestation)
- [`PendingAttestation`](#pendingattestation)
- [`Eth1Data`](#eth1data)
Expand Down Expand Up @@ -55,7 +54,6 @@
- [`hash_tree_root`](#hash_tree_root)
- [`signing_root`](#signing_root)
- [`bls_verify`](#bls_verify)
- [`bls_verify_multiple`](#bls_verify_multiple)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
- [Predicates](#predicates)
- [`is_active_validator`](#is_active_validator)
Expand Down Expand Up @@ -308,20 +306,11 @@ class AttestationData(Container):
target: Checkpoint
```

#### `AttestationDataAndCustodyBit`

```python
class AttestationDataAndCustodyBit(Container):
data: AttestationData
custody_bit: bit # Challengeable bit (SSZ-bool, 1 byte) for the custody of shard data
```

#### `IndexedAttestation`

```python
class IndexedAttestation(Container):
custody_bit_0_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] # Indices with custody bit equal to 0
custody_bit_1_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] # Indices with custody bit equal to 1
attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData
signature: BLSSignature
```
Expand Down Expand Up @@ -399,7 +388,6 @@ class AttesterSlashing(Container):
class Attestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData
custody_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
signature: BLSSignature
```

Expand Down Expand Up @@ -553,10 +541,6 @@ def bytes_to_int(data: bytes) -> uint64:

`bls_verify` is a function for verifying a BLS signature, as defined in the [BLS Signature spec](../bls_signature.md#bls_verify).

#### `bls_verify_multiple`

`bls_verify_multiple` is a function for verifying a BLS signature constructed from multiple messages, as defined in the [BLS Signature spec](../bls_signature.md#bls_verify_multiple).

#### `bls_aggregate_pubkeys`

`bls_aggregate_pubkeys` is a function for aggregating multiple BLS public keys into a single aggregate key, as defined in the [BLS Signature spec](../bls_signature.md#bls_aggregate_pubkeys).
Expand Down Expand Up @@ -605,31 +589,18 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
"""
Check if ``indexed_attestation`` has valid indices and signature.
"""
bit_0_indices = indexed_attestation.custody_bit_0_indices
bit_1_indices = indexed_attestation.custody_bit_1_indices
indices = indexed_attestation.attesting_indices

# Verify no index has custody bit equal to 1 [to be removed in phase 1]
if not len(bit_1_indices) == 0: # [to be removed in phase 1]
return False # [to be removed in phase 1]
# Verify max number of indices
if not len(bit_0_indices) + len(bit_1_indices) <= MAX_VALIDATORS_PER_COMMITTEE:
return False
# Verify index sets are disjoint
if not len(set(bit_0_indices).intersection(bit_1_indices)) == 0:
if not len(indices) <= MAX_VALIDATORS_PER_COMMITTEE:
return False
# Verify indices are sorted
if not (bit_0_indices == sorted(bit_0_indices) and bit_1_indices == sorted(bit_1_indices)):
if not indices == sorted(indices):
return False
# Verify aggregate signature
if not bls_verify_multiple(
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
pubkeys=[
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_0_indices]),
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_1_indices]),
],
message_hashes=[
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)),
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)),
],
if not bls_verify(
pubkey=bls_aggregate_pubkeys([state.validators[i].pubkey for i in indices]),
message_hash=hash_tree_root(indexed_attestation.data),
signature=indexed_attestation.signature,
domain=get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch),
):
Expand Down Expand Up @@ -922,13 +893,9 @@ 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)
custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_bits)
assert custody_bit_1_indices.issubset(attesting_indices)
custody_bit_0_indices = attesting_indices.difference(custody_bit_1_indices)

return IndexedAttestation(
custody_bit_0_indices=sorted(custody_bit_0_indices),
custody_bit_1_indices=sorted(custody_bit_1_indices),
attesting_indices=sorted(attesting_indices),
data=attestation.data,
signature=attestation.signature,
)
Expand Down Expand Up @@ -1460,9 +1427,8 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla
assert is_valid_indexed_attestation(state, attestation_2)

slashed_any = False
attesting_indices_1 = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
attesting_indices_2 = attestation_2.custody_bit_0_indices + attestation_2.custody_bit_1_indices
for index in sorted(set(attesting_indices_1).intersection(attesting_indices_2)):
indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
for index in sorted(indices):
if is_slashable_validator(state.validators[index], get_current_epoch(state)):
slash_validator(state, index)
slashed_any = True
Expand All @@ -1479,7 +1445,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH

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

pending_attestation = PendingAttestation(
data=data,
Expand Down
2 changes: 1 addition & 1 deletion specs/core/0_fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
assert is_valid_indexed_attestation(target_state, indexed_attestation)

# Update latest messages
for i in indexed_attestation.custody_bit_0_indices + indexed_attestation.custody_bit_1_indices:
for i in indexed_attestation.attesting_indices:
if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch:
store.latest_messages[i] = LatestMessage(epoch=target.epoch, root=attestation.data.beacon_block_root)
```
21 changes: 1 addition & 20 deletions specs/validator/0_beacon-chain-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,13 @@
- [Construct attestation](#construct-attestation)
- [Data](#data)
- [Aggregation bits](#aggregation-bits)
- [Custody bits](#custody-bits)
- [Aggregate signature](#aggregate-signature)
- [Broadcast attestation](#broadcast-attestation)
- [Attestation aggregation](#attestation-aggregation)
- [Aggregation selection](#aggregation-selection)
- [Construct aggregate](#construct-aggregate)
- [Data](#data-1)
- [Aggregation bits](#aggregation-bits-1)
- [Custody bits](#custody-bits-1)
- [Aggregate signature](#aggregate-signature-1)
- [Broadcast aggregate](#broadcast-aggregate)
- [`AggregateAndProof`](#aggregateandproof)
Expand Down Expand Up @@ -331,25 +329,14 @@ Set `attestation.data = attestation_data` where `attestation_data` is the `Attes

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

##### Custody bits

- Let `attestation.custody_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` filled with zeros of length `len(committee)`.

*Note*: This is a stub for Phase 0.

##### Aggregate signature

Set `attestation.signature = signed_attestation_data` where `signed_attestation_data` is obtained from:

```python
def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestation, privkey: int) -> BLSSignature:
attestation_data_and_custody_bit = AttestationDataAndCustodyBit(
data=attestation.data,
custody_bit=0b0,
)

domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch)
return bls_sign(privkey, hash_tree_root(attestation_data_and_custody_bit), domain)
return bls_sign(privkey, hash_tree_root(attestation.data), domain)
```

#### Broadcast attestation
Expand Down Expand Up @@ -391,12 +378,6 @@ Set `aggregate_attestation.data = attestation_data` where `attestation_data` is

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

##### Custody bits

- Let `aggregate_attestation.custody_bits` be a `Bitlist[MAX_VALIDATORS_PER_COMMITTEE]` filled with zeros of length `len(committee)`.

*Note*: This is a stub for Phase 0.

##### Aggregate signature

Set `aggregate_attestation.signature = aggregate_signature` where `aggregate_signature` is obtained from:
Expand Down
2 changes: 1 addition & 1 deletion test_libs/pyspec/eth2spec/fuzzing/test_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def test_decoder():
rng = Random(123)

# check these types only, Block covers a lot of operation types already.
for typ in [spec.AttestationDataAndCustodyBit, spec.BeaconState, spec.BeaconBlock]:
for typ in [spec.Attestation, spec.BeaconState, spec.BeaconBlock]:
# create a random pyspec value
original = random_value.get_random_ssz_object(rng, typ, 100, 10,
mode=random_value.RandomizationMode.mode_random,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@

from eth2spec.test.context import with_all_phases, spec_state_test, with_phases


from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
from eth2spec.test.helpers.attestations import get_valid_attestation
from eth2spec.test.helpers.state import state_transition_and_sign_block
Expand All @@ -19,7 +17,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
indexed_attestation = spec.get_indexed_attestation(state, attestation)
spec.on_attestation(store, attestation)
assert (
store.latest_messages[indexed_attestation.custody_bit_0_indices[0]] ==
store.latest_messages[indexed_attestation.attesting_indices[0]] ==
spec.LatestMessage(
epoch=attestation.data.target.epoch,
root=attestation.data.beacon_block_root,
Expand Down Expand Up @@ -100,7 +98,7 @@ def test_on_attestation_same_slot(spec, state):
run_on_attestation(spec, state, store, attestation, False)


@with_phases(['phase0'])
@with_all_phases
@spec_state_test
def test_on_attestation_invalid_attestation(spec, state):
store = spec.get_genesis_store(state)
Expand All @@ -113,6 +111,7 @@ def test_on_attestation_invalid_attestation(spec, state):
spec.on_block(store, block)

attestation = get_valid_attestation(spec, state, slot=block.slot)
# make attestation invalid by setting a phase1-only custody bit
attestation.custody_bits[0] = 1
# make invalid by using an invalid committee index
attestation.data.index = spec.MAX_COMMITTEES_PER_SLOT * spec.SLOTS_PER_EPOCH

run_on_attestation(spec, state, store, attestation, False)
13 changes: 3 additions & 10 deletions test_libs/pyspec/eth2spec/test/helpers/attestations.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@ def get_valid_attestation(spec, state, slot=None, index=None, signed=False):

committee_size = len(beacon_committee)
aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size))
custody_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size))
attestation = spec.Attestation(
aggregation_bits=aggregation_bits,
data=attestation_data,
custody_bits=custody_bits,
)
fill_aggregate_attestation(spec, state, attestation)
if signed:
Expand All @@ -83,7 +81,7 @@ def sign_aggregate_attestation(spec, state, attestation_data, participants: List


def sign_indexed_attestation(spec, state, indexed_attestation):
participants = indexed_attestation.custody_bit_0_indices + indexed_attestation.custody_bit_1_indices
participants = indexed_attestation.attesting_indices
indexed_attestation.signature = sign_aggregate_attestation(spec, state, indexed_attestation.data, participants)


Expand All @@ -97,14 +95,9 @@ def sign_attestation(spec, state, attestation):
attestation.signature = sign_aggregate_attestation(spec, state, attestation.data, participants)


def get_attestation_signature(spec, state, attestation_data, privkey, custody_bit=0b0):
message_hash = spec.AttestationDataAndCustodyBit(
data=attestation_data,
custody_bit=custody_bit,
).hash_tree_root()

def get_attestation_signature(spec, state, attestation_data, privkey):
return bls_sign(
message_hash=message_hash,
message_hash=attestation_data.hash_tree_root(),
privkey=privkey,
domain=spec.get_domain(
state=state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
spec_state_test,
expect_assertion_error,
always_bls, never_bls,
with_all_phases, with_phases,
with_all_phases,
spec_test,
low_balances,
with_custom_state,
Expand Down Expand Up @@ -274,35 +274,6 @@ def test_bad_source_root(spec, state):
yield from run_attestation_processing(spec, state, attestation, False)


@with_all_phases
@spec_state_test
def test_inconsistent_bits(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY

custody_bits = attestation.custody_bits[:]
custody_bits.append(False)

attestation.custody_bits = custody_bits

sign_attestation(spec, state, attestation)

yield from run_attestation_processing(spec, state, attestation, False)


@with_phases(['phase0'])
@spec_state_test
def test_non_empty_custody_bits(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY

attestation.custody_bits = attestation.aggregation_bits[:]

sign_attestation(spec, state, attestation)

yield from run_attestation_processing(spec, state, attestation, False)


@with_all_phases
@spec_state_test
def test_empty_aggregation_bits(spec, state):
Expand Down Expand Up @@ -344,32 +315,3 @@ def test_too_few_aggregation_bits(spec, state):
attestation.aggregation_bits = attestation.aggregation_bits[:-1]

yield from run_attestation_processing(spec, state, attestation, False)


@with_all_phases
@spec_state_test
def test_too_many_custody_bits(spec, state):
attestation = get_valid_attestation(spec, state, signed=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY

# one too many bits
attestation.custody_bits.append(0b0)

yield from run_attestation_processing(spec, state, attestation, False)


@with_all_phases
@spec_state_test
def test_too_few_custody_bits(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY

attestation.custody_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](
*([0b1] + [0b0] * (len(attestation.custody_bits) - 1)))

sign_attestation(spec, state, attestation)

# one too few bits
attestation.custody_bits = attestation.custody_bits[:-1]

yield from run_attestation_processing(spec, state, attestation, False)
Loading