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

Compact committee roots #1219

Merged
merged 11 commits into from
Jun 29, 2019
2 changes: 1 addition & 1 deletion configs/constant_presets/mainnet.yaml
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ SHARD_COUNT: 1024
# 2**7 (= 128)
TARGET_COMMITTEE_SIZE: 128
# 2**12 (= 4,096)
MAX_INDICES_PER_ATTESTATION: 4096
MAX_VALIDATORS_PER_COMMITTEE: 4096
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**16 (= 65,536)
2 changes: 1 addition & 1 deletion configs/constant_presets/minimal.yaml
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ SHARD_COUNT: 8
# [customized] unsecure, but fast
TARGET_COMMITTEE_SIZE: 4
# 2**12 (= 4,096)
MAX_INDICES_PER_ATTESTATION: 4096
MAX_VALIDATORS_PER_COMMITTEE: 4096
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**16 (= 65,536)
71 changes: 42 additions & 29 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
- [`Eth1Data`](#eth1data)
- [`HistoricalBatch`](#historicalbatch)
- [`DepositData`](#depositdata)
- [`CompactCommittee`](#compactcommittee)
- [`BeaconBlockHeader`](#beaconblockheader)
- [Beacon operations](#beacon-operations)
- [`ProposerSlashing`](#proposerslashing)
@@ -69,7 +70,7 @@
- [`get_block_root_at_slot`](#get_block_root_at_slot)
- [`get_block_root`](#get_block_root)
- [`get_randao_mix`](#get_randao_mix)
- [`get_active_index_root`](#get_active_index_root)
- [`get_compact_committees_root`](#get_compact_committees_root)
- [`generate_seed`](#generate_seed)
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
- [`verify_merkle_branch`](#verify_merkle_branch)
@@ -188,7 +189,7 @@ The following values are (non-configurable) constants used throughout the specif
| - | - |
| `SHARD_COUNT` | `2**10` (= 1,024) |
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
| `MAX_INDICES_PER_ATTESTATION` | `2**12` (= 4,096) |
| `MAX_VALIDATORS_PER_COMMITTEE` | `2**12` (= 4,096) |
| `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) |
| `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) |
| `SHUFFLE_ROUND_COUNT` | `90` |
@@ -351,8 +352,8 @@ class AttestationDataAndCustodyBit(Container):

```python
class IndexedAttestation(Container):
custody_bit_0_indices: List[ValidatorIndex, MAX_INDICES_PER_ATTESTATION] # Indices with custody bit equal to 0
custody_bit_1_indices: List[ValidatorIndex, MAX_INDICES_PER_ATTESTATION] # Indices with custody bit equal to 1
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
data: AttestationData
signature: BLSSignature
```
@@ -361,7 +362,7 @@ class IndexedAttestation(Container):

```python
class PendingAttestation(Container):
aggregation_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8]
aggregation_bitfield: Bytes[MAX_VALIDATORS_PER_COMMITTEE // 8]
data: AttestationData
inclusion_delay: Slot
proposer_index: ValidatorIndex
@@ -394,6 +395,14 @@ class DepositData(Container):
signature: BLSSignature
```

#### `CompactCommittee`

```python
class CompactCommittee(Container):
pubkeys: List[Bytes48, MAX_VALIDATORS_PER_COMMITTEE]
compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE]
```

#### `BeaconBlockHeader`

```python
@@ -428,9 +437,9 @@ class AttesterSlashing(Container):

```python
class Attestation(Container):
aggregation_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8]
aggregation_bitfield: Bytes[MAX_VALIDATORS_PER_COMMITTEE // 8]
data: AttestationData
custody_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8]
custody_bitfield: Bytes[MAX_VALIDATORS_PER_COMMITTEE // 8]
signature: BLSSignature
```

@@ -518,7 +527,7 @@ class BeaconState(Container):
# Shuffling
start_shard: Shard
randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR]
active_index_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Active registry digests for light clients
compact_committees_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Committee digests for light clients
# Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
# Attestations
@@ -692,6 +701,9 @@ def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:

```python
def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
"""
Return the start shard of the 0th committee in an epoch.
"""
assert epoch <= get_current_epoch(state) + 1
check_epoch = Epoch(get_current_epoch(state) + 1)
shard = Shard((state.start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT)
@@ -745,17 +757,25 @@ def get_randao_mix(state: BeaconState,
return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
```

### `get_active_index_root`
### `get_compact_committees_root`

```python
def get_active_index_root(state: BeaconState,
epoch: Epoch) -> Hash:
def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash:
"""
Return the index root at a recent ``epoch``.
``epoch`` expected to be between
(current_epoch - EPOCHS_PER_HISTORICAL_VECTOR + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY].
Return the compact committee root for the current epoch.
"""
return state.active_index_roots[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
committees = [CompactCommittee() for _ in range(SHARD_COUNT)]
start_shard = get_epoch_start_shard(state, epoch)
for committee_number in range(get_epoch_committee_count(state, epoch)):
shard = Shard((start_shard + committee_number) % SHARD_COUNT)
for index in get_crosslink_committee(state, epoch, shard):
validator = state.validators[index]
committees[shard].pubkeys.append(validator.pubkey)
compact_balance = validator.effective_balance // EFFECTIVE_BALANCE_INCREMENT
# `index` (top 6 bytes) + `slashed` (16th bit) + `compact_balance` (bottom 15 bits)
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
compact_validator = uint64((index << 16) + (validator.slashed << 15) + compact_balance)
committees[shard].compact_validators.append(compact_validator)
return hash_tree_root(Vector[CompactCommittee, SHARD_COUNT](committees))
```

### `generate_seed`
@@ -768,7 +788,7 @@ def generate_seed(state: BeaconState,
"""
return hash(
get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) +
get_active_index_root(state, epoch) +
hash_tree_root(List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, epoch))) +
int_to_bytes(epoch, length=32)
)
```
@@ -974,7 +994,7 @@ def validate_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
# Verify no index has custody bit equal to 1 [to be removed in phase 1]
assert len(bit_1_indices) == 0
# Verify max number of indices
assert len(bit_0_indices) + len(bit_1_indices) <= MAX_INDICES_PER_ATTESTATION
assert len(bit_0_indices) + len(bit_1_indices) <= MAX_VALIDATORS_PER_COMMITTEE
# Verify index sets are disjoint
assert len(set(bit_0_indices).intersection(bit_1_indices)) == 0
# Verify indices are sorted
@@ -1176,12 +1196,9 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth
validator.activation_epoch = GENESIS_EPOCH

# Populate active_index_roots
genesis_active_index_root = hash_tree_root(
List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, GENESIS_EPOCH))
)
genesis_committee_root = get_compact_committees_root(state, GENESIS_EPOCH)
for index in range(EPOCHS_PER_HISTORICAL_VECTOR):
state.active_index_roots[index] = genesis_active_index_root

state.compact_committees_roots[index] = genesis_committee_root
return state
```

@@ -1505,7 +1522,7 @@ def process_slashings(state: BeaconState) -> None:
```python
def process_final_updates(state: BeaconState) -> None:
current_epoch = get_current_epoch(state)
next_epoch = current_epoch + 1
next_epoch = Shard(current_epoch + 1)
protolambda marked this conversation as resolved.
Show resolved Hide resolved
# Reset eth1 data votes
if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
state.eth1_data_votes = []
@@ -1518,12 +1535,8 @@ def process_final_updates(state: BeaconState) -> None:
# Update start shard
state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
# Set active index root
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % EPOCHS_PER_HISTORICAL_VECTOR
state.active_index_roots[index_root_position] = hash_tree_root(
List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](
get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY))
)
)
committee_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % EPOCHS_PER_HISTORICAL_VECTOR
state.compact_committees_roots[committee_root_position] = get_compact_committees_root(state, next_epoch)
# Reset slashings
state.slashings[next_epoch % EPOCHS_PER_SLASHINGS_VECTOR] = Gwei(0)
# Set randao mix
4 changes: 2 additions & 2 deletions specs/light_client/sync_protocol.md
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ We define an "expansion" of an object as an object where a field in an object th

We define two expansions:

* `ExtendedBeaconState`, which is identical to a `BeaconState` except `active_index_roots: List[Bytes32]` is replaced by `active_indices: List[List[ValidatorIndex]]`, where `BeaconState.active_index_roots[i] = hash_tree_root(ExtendedBeaconState.active_indices[i])`.
* `ExtendedBeaconState`, which is identical to a `BeaconState` except `compact_committees_roots: List[Bytes32]` is replaced by `active_indices: List[List[ValidatorIndex]]`, where `BeaconState.compact_committees_roots[i] = hash_tree_root(ExtendedBeaconState.active_indices[i])`.
* `ExtendedBeaconBlock`, which is identical to a `BeaconBlock` except `state_root` is replaced with the corresponding `state: ExtendedBeaconState`.

### `get_active_validator_indices`
@@ -40,7 +40,7 @@ Note that there is now a new way to compute `get_active_validator_indices`:

```python
def get_active_validator_indices(state: ExtendedBeaconState, epoch: Epoch) -> List[ValidatorIndex]:
return state.active_indices[epoch % ACTIVE_INDEX_ROOTS_LENGTH]
return state.active_indices[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
```

Note that it takes `state` instead of `state.validators` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments.
4 changes: 2 additions & 2 deletions test_libs/pyspec/eth2spec/test/helpers/genesis.py
Original file line number Diff line number Diff line change
@@ -43,9 +43,9 @@ def create_genesis_state(spec, num_validators):
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
validator.activation_epoch = spec.GENESIS_EPOCH

genesis_active_index_root = hash_tree_root(List[spec.ValidatorIndex, spec.VALIDATOR_REGISTRY_LIMIT](
genesis_compact_committees_root = hash_tree_root(List[spec.ValidatorIndex, spec.VALIDATOR_REGISTRY_LIMIT](
spec.get_active_validator_indices(state, spec.GENESIS_EPOCH)))
for index in range(spec.EPOCHS_PER_HISTORICAL_VECTOR):
state.active_index_roots[index] = genesis_active_index_root
state.compact_committees_roots[index] = genesis_compact_committees_root

return state