Merge pull request #631 from ethereum/dev

Weekly release dev into master
This commit is contained in:
Danny Ryan 2019-02-15 10:05:35 -07:00 committed by GitHub
commit c00d1d640b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 463 additions and 338 deletions

File diff suppressed because it is too large Load Diff

View File

@ -16,10 +16,12 @@ Ethereum 2.0 consists of a central beacon chain along with `SHARD_COUNT` shard c
Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md#constants) in addition to the following:
| Constant | Value | Unit | Approximation |
|------------------------|-----------------|-------|---------------|
| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | |
| `SHARD_BLOCK_SIZE` | 2**14 (= 16384) | bytes | |
| Constant | Value | Unit | Approximation |
|-------------------------------|------------------|--------|---------------|
| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | |
| `SHARD_BLOCK_SIZE` | 2**14 (= 16,384) | bytes | |
| `CROSSLINK_LOOKBACK` | 2**5 (= 32) | slots | |
| `PERSISTENT_COMMITTEE_PERIOD` | 2**11 (= 2,048) | epochs | 9 days |
### Flags, domains, etc.
@ -28,6 +30,89 @@ Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md
| `SHARD_PROPOSER_DOMAIN`| 129 |
| `SHARD_ATTESTER_DOMAIN`| 130 |
## Helper functions
#### get_split_offset
````python
def get_split_offset(list_size: int, chunks: int, index: int) -> int:
"""
Returns a value such that for a list L, chunk count k and index i,
split(L, k)[i] == L[get_split_offset(len(L), k, i): get_split_offset(len(L), k+1, i)]
"""
return (len(list_size) * index) // chunks
````
#### get_shuffled_committee
```python
def get_shuffled_committee(state: BeaconState,
shard: Shard,
committee_start_epoch: Epoch) -> List[ValidatorIndex]:
"""
Return shuffled committee.
"""
validator_indices = get_active_validator_indices(state.validators, committee_start_epoch)
seed = generate_seed(state, committee_start_epoch)
start_offset = get_split_offset(len(validator_indices), SHARD_COUNT, shard)
end_offset = get_split_offset(len(validator_indices), SHARD_COUNT, shard + 1)
return [
validator_indices[get_permuted_index(i, len(validator_indices), seed)]
for i in range(start_offset, end_offset)
]
```
#### get_persistent_committee
```python
def get_persistent_committee(state: BeaconState,
shard: Shard,
epoch: Epoch) -> List[ValidatorIndex]:
"""
Return the persistent committee for the given ``shard`` at the given ``epoch``.
"""
earlier_committee_start_epoch = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2
earlier_committee = get_shuffled_committee(state, shard, earlier_committee_start_epoch)
later_committee_start_epoch = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD
later_committee = get_shuffled_committee(state, shard, later_committee_start_epoch)
def get_switchover_epoch(index):
return (
bytes_to_int(hash(earlier_seed + bytes3(index))[0:8]) %
PERSISTENT_COMMITTEE_PERIOD
)
# Take not-yet-cycled-out validators from earlier committee and already-cycled-in validators from
# later committee; return a sorted list of the union of the two, deduplicated
return sorted(list(set(
[i for i in earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(i)] +
[i for i in later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(i)]
)))
```
#### get_shard_proposer_index
```python
def get_shard_proposer_index(state: BeaconState,
shard: Shard,
slot: Slot) -> ValidatorIndex:
seed = hash(
state.current_shuffling_seed +
int_to_bytes8(shard) +
int_to_bytes8(slot)
)
persistent_committee = get_persistent_committee(state, shard, slot_to_epoch(slot))
# Default proposer
index = bytes_to_int(seed[0:8]) % len(persistent_committee)
# If default proposer exits, try the other proposers in order; if all are exited
# return None (ie. no block can be proposed)
validators_to_try = persistent_committee[index:] + persistent_committee[:index]
for index in validators_to_try:
if is_active_validator(state.validators[index], get_current_epoch(state)):
return index
return None
```
## Data Structures
### Shard chain blocks
@ -40,50 +125,43 @@ A `ShardBlock` object has the following fields:
'slot': 'uint64',
# What shard is it on
'shard_id': 'uint64',
# Parent block's hash of root
'parent_root': 'hash32',
# Parent block's root
'parent_root': 'bytes32',
# Beacon chain block
'beacon_chain_ref': 'hash32',
# Depth of the Merkle tree
'data_tree_depth': 'uint8',
'beacon_chain_ref': 'bytes32',
# Merkle root of data
'data_root': 'hash32'
'data_root': 'bytes32'
# State root (placeholder for now)
'state_root': 'hash32',
'state_root': 'bytes32',
# Block signature
'signature': ['uint384'],
'signature': 'bytes96',
# Attestation
'participation_bitfield': 'bytes',
'aggregate_signature': ['uint384'],
'aggregate_signature': 'bytes96',
}
```
## Shard block processing
For a block on a shard to be processed by a node, the following conditions must be met:
For a `shard_block` on a shard to be processed by a node, the following conditions must be met:
* The `ShardBlock` pointed to by `parent_root` has already been processed and accepted
* The `ShardBlock` pointed to by `shard_block.parent_root` has already been processed and accepted
* The signature for the block from the _proposer_ (see below for definition) of that block is included along with the block in the network message object
To validate a block header on shard `shard_id`, compute as follows:
To validate a block header on shard `shard_block.shard_id`, compute as follows:
* Verify that `beacon_chain_ref` is the hash of a block in the beacon chain with slot less than or equal to `slot`. Verify that `beacon_chain_ref` is equal to or a descendant of the `beacon_chain_ref` specified in the `ShardBlock` pointed to by `parent_root`.
* Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. Let `validators` be `[validators[i] for i in state.current_persistent_committees[shard_id]]`.
* Assert `len(participation_bitfield) == ceil_div8(len(validators))`
* Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_id) + int_to_bytes8(slot)) % len(validators)`. Let `msg` be the block but with the `block.signature` set to `[0, 0]`. Verify that `BLSVerify(pub=validators[proposer_index].pubkey, msg=hash(msg), sig=block.signature, domain=get_domain(state, slot, SHARD_PROPOSER_DOMAIN))` passes.
* Generate the `group_public_key` by adding the public keys of all the validators for whom the corresponding position in the bitfield is set to 1. Verify that `BLSVerify(pub=group_public_key, msg=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes.
### Block Merklization helper
```python
def merkle_root(block_body):
assert len(block_body) == SHARD_BLOCK_SIZE
chunks = SHARD_BLOCK_SIZE // SHARD_CHUNK_SIZE
o = [0] * chunks + [block_body[i * SHARD_CHUNK_SIZE: (i+1) * SHARD_CHUNK_SIZE] for i in range(chunks)]
for i in range(chunks-1, 0, -1):
o[i] = hash(o[i*2] + o[i*2+1])
return o[1]
```
* Verify that `shard_block.beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`.
* Verify that `shard_block.beacon_chain_ref` is equal to or a descendant of the `shard_block.beacon_chain_ref` specified in the `ShardBlock` pointed to by `shard_block.parent_root`.
* Let `state` be the state of the beacon chain block referred to by `shard_block.beacon_chain_ref`.
* Let `persistent_committee = get_persistent_committee(state, shard_block.shard_id, slot_to_epoch(shard_block.slot))`.
* Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))`
* For every `i in range(len(persistent_committee))` where `is_active_validator(state.validators[persistent_committee[i]], get_current_epoch(state))` returns `False`, verify that `get_bitfield_bit(shard_block.participation_bitfield, i) == 0`
* Let `proposer_index = get_shard_proposer_index(state, shard_block.shard_id, shard_block.slot)`.
* Verify that `proposer_index` is not `None`.
* Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`.
* Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes.
* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`.
* Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes.
### Verifying shard block data
@ -98,27 +176,49 @@ A node should sign a crosslink only if the following conditions hold. **If a nod
First, the conditions must recursively apply to the crosslink referenced in `last_crosslink_root` for the same shard (unless `last_crosslink_root` equals zero, in which case we are at the genesis).
Second, we verify the `shard_block_combined_data_root`. Let `h` be the slot _immediately after_ the slot of the shard block included by the last crosslink, and `h+n-1` be the slot number of the block directly referenced by the current `shard_block_root`. Let `B[i]` be the block at slot `h+i` in the shard chain. Let `bodies[0] .... bodies[n-1]` be the bodies of these blocks and `roots[0] ... roots[n-1]` the data roots. If there is a missing slot in the shard chain at position `h+i`, then `bodies[i] == b'\x00' * shard_block_maxbytes(state[i])` and `roots[i]` be the Merkle root of the empty data. Define `compute_merkle_root` be a simple Merkle root calculating function that takes as input a list of objects, where the list's length must be an exact power of two. We define the function for computing the combined data root as follows:
Second, we verify the `shard_chain_commitment`.
* Let `start_slot = state.latest_crosslinks[shard].epoch * SLOTS_PER_EPOCH + SLOTS_PER_EPOCH - CROSSLINK_LOOKBACK`.
* Let `end_slot = attestation.data.slot - attestation.data.slot % SLOTS_PER_EPOCH - CROSSLINK_LOOKBACK`.
* Let `length = end_slot - start_slot`, `headers[0] .... headers[length-1]` be the serialized block headers in the canonical shard chain from the verifer's point of view (note that this implies that `headers` and `bodies` have been checked for validity).
* Let `bodies[0] ... bodies[length-1]` be the bodies of the blocks.
* Note: If there is a missing slot, then the header and body are the same as that of the block at the most recent slot that has a block.
We define two helpers:
```python
ZERO_ROOT = merkle_root(bytes([0] * SHARD_BLOCK_SIZE))
def mk_combined_data_root(roots):
data = roots + [ZERO_ROOT for _ in range(len(roots), next_power_of_2(len(roots)))]
return compute_merkle_root(data)
def pad_to_power_of_2(values: List[bytes]) -> List[bytes]:
zero_shard_block = b'\x00' * SHARD_BLOCK_SIZE
while not is_power_of_two(len(values)):
values = values + [zero_shard_block]
return values
```
This outputs the root of a tree of the data roots, with the data roots all adjusted to have the same height if needed. The tree can also be viewed as a tree of all of the underlying data concatenated together, appropriately padded. Here is an equivalent definition that uses bodies instead of roots [TODO: check equivalence]:
```python
def mk_combined_data_root(depths, bodies):
data = b''.join(bodies)
data += bytes([0] * (next_power_of_2(len(data)) - len(data))
return compute_merkle_root([data[pos:pos+SHARD_CHUNK_SIZE] for pos in range(0, len(data), SHARD_CHUNK_SIZE)])
def merkle_root_of_bytes(data: bytes) -> bytes:
return merkle_root([data[i:i + 32] for i in range(0, len(data), 32)])
```
Verify that the `shard_block_combined_data_root` is the output of these functions.
We define the function for computing the commitment as follows:
```python
def compute_commitment(headers: List[ShardBlock], bodies: List[bytes]) -> Bytes32:
return hash(
merkle_root(
pad_to_power_of_2([
merkle_root_of_bytes(zpad(serialize(h), SHARD_BLOCK_SIZE)) for h in headers
])
) +
merkle_root(
pad_to_power_of_2([
merkle_root_of_bytes(h) for h in bodies
])
)
)
```
The `shard_chain_commitment` is only valid if it equals `compute_commitment(headers, bodies)`.
### Shard block fork choice rule
The fork choice rule for any shard is LMD GHOST using the validators currently assigned to that shard, but instead of being rooted in the genesis it is rooted in the block referenced in the most recent accepted crosslink (ie. `state.crosslinks[shard].shard_block_root`). Only blocks whose `beacon_chain_ref` is the block in the main beacon chain at the specified `slot` should be considered (if the beacon chain skips a slot, then the block at that slot is considered to be the block in the beacon chain at the highest slot lower than a slot).
The fork choice rule for any shard is LMD GHOST using the shard chain attestations of the persistent committee and the beacon chain attestations of the crosslink committee currently assigned to that shard, but instead of being rooted in the genesis it is rooted in the block referenced in the most recent accepted crosslink (ie. `state.crosslinks[shard].shard_block_root`). Only blocks whose `beacon_chain_ref` is the block in the main beacon chain at the specified `slot` should be considered (if the beacon chain skips a slot, then the block at that slot is considered to be the block in the beacon chain at the highest slot lower than a slot).

View File

@ -9,28 +9,24 @@ deserializing objects and data types.
## ToC
* [About](#about)
* [Terminology](#terminology)
* [Variables and Functions](#variables-and-functions)
* [Constants](#constants)
* [Overview](#overview)
+ [Serialize/Encode](#serializeencode)
- [uint](#uint)
- [Bool](#bool)
- [Bytes](#bytes)
- [bytesN](#bytesn)
- [bytes](#bytes-1)
- [uintN](#uintn)
- [bool](#bool)
- [bytesN](#bytesn)
- [List/Vectors](#listvectors)
- [Container](#container)
+ [Deserialize/Decode](#deserializedecode)
- [uint](#uint-1)
- [Bool](#bool-1)
- [Bytes](#bytes-2)
- [bytesN](#bytesn-1)
- [bytes](#bytes-1)
- [uintN](#uintn-1)
- [bool](#bool-1)
- [bytesN](#bytesn-1)
- [List/Vectors](#listvectors-1)
- [Container](#container-1)
+ [Tree Hash](#tree-hash)
- [`uint8`..`uint256`, `bool`, `bytes1`..`bytes32`](#uint8uint256-bool-bytes1bytes32)
- [`uint264`..`uintN`, `bytes`, `bytes33`..`bytesN`](#uint264uintn-bytes-bytes33bytesn)
- [`uint264`..`uintN`, `bytes33`..`bytesN`](#uint264uintn-bytes33bytesn)
- [List/Vectors](#listvectors-2)
- [Container](#container-2)
* [Implementations](#implementations)
@ -68,11 +64,11 @@ overhead.
### Serialize/Encode
#### uint
#### uintN
| uint Type | Usage |
|:---------:|:-----------------------------------------------------------|
| `uintN` | Type of `N` bits unsigned integer, where ``N % 8 == 0``. |
| `uintN` | Type of `N` bits unsigned integer, where ``N % 8 == 0``. |
Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
@ -88,7 +84,7 @@ buffer_size = int_size / 8
return value.to_bytes(buffer_size, 'little')
```
#### Bool
#### bool
Convert directly to a single 0x00 or 0x01 byte.
@ -101,18 +97,13 @@ assert(value in (True, False))
return b'\x01' if value is True else b'\x00'
```
#### Bytes
#### bytesN
| Bytes Type | Usage |
|:---------:|:------------------------------------|
| `bytesN` | Explicit length `N` bytes data. |
| `bytes` | Bytes data with arbitrary length. |
##### bytesN
A fixed-size byte array.
| Checks to perform | Code |
|:---------------------------------------|:---------------------|
| Length in bytes is correct for `bytesN` | ``len(value) == N`` |
| Length in bytes is correct for `bytesN` | ``len(value) == N`` |
```python
assert(len(value) == N)
@ -120,21 +111,6 @@ assert(len(value) == N)
return value
```
##### bytes
For general `bytes` type:
1. Get the length/number of bytes; Encode into a `4-byte` integer.
2. Append the value to the length and return: ``[ length_bytes ] + [ value_bytes ]``
| Check to perform | Code |
|:-------------------------------------|:-----------------------|
| Length of bytes can fit into 4 bytes | ``len(value) < 2**32`` |
```python
assert(len(value) < 2**32)
byte_length = (len(value)).to_bytes(LENGTH_BYTES, 'little')
return byte_length + value
```
#### List/Vectors
Lists are a collection of elements of the same homogeneous type.
@ -146,6 +122,8 @@ Lists are a collection of elements of the same homogeneous type.
1. Serialize all list elements individually and concatenate them.
2. Prefix the concatenation with its length encoded as a `4-byte` **little-endian** unsigned integer.
We define `bytes` to be a synonym of `List[bytes1]`.
**Example in Python**
```python
@ -168,8 +146,8 @@ A container represents a heterogenous, associative collection of key-value pairs
To serialize a container, obtain the list of its field's names in the specified order. For each field name in this list, obtain the corresponding value and serialize it. Tightly pack the complete set of serialized values in the same order as the field names into a buffer. Calculate the size of this buffer of serialized bytes and encode as a `4-byte` **little endian** `uint32`. Prepend the encoded length to the buffer. The result of this concatenation is the final serialized value of the container.
| Check to perform | Code |
|:--------------------------------------------|:----------------------------|
| Check to perform | Code |
|:----------------------------------------------|:----------------------------|
| Length of serialized fields fits into 4 bytes | ``len(serialized) < 2**32`` |
To serialize:
@ -231,7 +209,7 @@ At the final step, the following checks should be made:
|:-------------------------|:-------------------------------------|
| Ensure no extra length | `new_index == len(rawbytes)` |
#### uint
#### uintN
Convert directly from bytes into integer utilising the number of bytes the same
size as the integer length. (e.g. ``uint16 == 2 bytes``)
@ -245,7 +223,7 @@ assert(len(rawbytes) >= new_index)
return int.from_bytes(rawbytes[current_index:current_index+byte_length], 'little'), new_index
```
#### Bool
#### bool
Return True if 0x01, False if 0x00.
@ -254,9 +232,7 @@ assert rawbytes in (b'\x00', b'\x01')
return True if rawbytes == b'\x01' else False
```
#### Bytes
##### bytesN
#### bytesN
Return the `N` bytes.
@ -266,28 +242,6 @@ new_index = current_index + N
return rawbytes[current_index:current_index+N], new_index
```
##### bytes
Get the length of the bytes, return the bytes.
| Check to perform | code |
|:--------------------------------------------------|:-------------------------------------------------|
| rawbytes has enough left for length | ``len(rawbytes) > current_index + LENGTH_BYTES`` |
| bytes to return not greater than serialized bytes | ``len(rawbytes) > bytes_end `` |
```python
assert(len(rawbytes) > current_index + LENGTH_BYTES)
bytes_length = int.from_bytes(rawbytes[current_index:current_index + LENGTH_BYTES], 'little')
bytes_start = current_index + LENGTH_BYTES
bytes_end = bytes_start + bytes_length
new_index = bytes_end
assert(len(rawbytes) >= bytes_end)
return rawbytes[bytes_start:bytes_end], new_index
```
#### List/Vectors
Deserialize each element in the list.
@ -295,7 +249,6 @@ Deserialize each element in the list.
2. Loop through deserializing each item in the list until you reach the
entire length of the list.
| Check to perform | code |
|:------------------------------------------|:----------------------------------------------------------------|
| ``rawbytes`` has enough left for length | ``len(rawbytes) > current_index + LENGTH_BYTES`` |
@ -384,7 +337,7 @@ Refer to [the helper function `hash`](https://github.com/ethereum/eth2.0-specs/b
Return the serialization of the value.
#### `uint264`..`uintN`, `bytes`, `bytes33`..`bytesN`
#### `uint264`..`uintN`, `bytes33`..`bytesN`
Return the hash of the serialization of the value.
@ -414,13 +367,16 @@ def merkle_hash(lst):
# Leave large items alone
chunkz = lst
# Tree-hash
while len(chunkz) > 1:
if len(chunkz) % 2 == 1:
chunkz.append(b'\x00' * SSZ_CHUNK_SIZE)
# Merkleise
def next_power_of_2(x):
return 1 if x == 0 else 2**(x - 1).bit_length()
for i in range(len(chunkz), next_power_of_2(len(chunkz))):
chunkz.append(b'\x00' * SSZ_CHUNK_SIZE)
while len(chunkz) > 1:
chunkz = [hash(chunkz[i] + chunkz[i+1]) for i in range(0, len(chunkz), 2)]
# Return hash of root and length data
# Return hash of root and data length
return hash(chunkz[0] + datalen)
```
@ -434,10 +390,10 @@ Where the inner `hash_tree_root_internal` is a recursive application of the tree
#### Container
Recursively tree hash the values in the container in the same order as the fields, and return the hash of the concatenation of the results.
Recursively tree hash the values in the container in the same order as the fields, and Merkle hash the results.
```python
return hash(b''.join([hash_tree_root_internal(getattr(x, field)) for field in value.fields]))
return merkle_hash([hash_tree_root_internal(getattr(x, field)) for field in value.fields])
```
## Implementations
@ -452,6 +408,7 @@ return hash(b''.join([hash_tree_root_internal(getattr(x, field)) for field in va
| Java | [ https://www.github.com/ConsenSys/cava/tree/master/ssz ](https://www.github.com/ConsenSys/cava/tree/master/ssz) | SSZ Java library part of the Cava suite |
| Go | [ https://github.com/prysmaticlabs/prysm/tree/master/shared/ssz ](https://github.com/prysmaticlabs/prysm/tree/master/shared/ssz) | Go implementation of SSZ mantained by Prysmatic Labs |
| Swift | [ https://github.com/yeeth/SimpleSerialize.swift ](https://github.com/yeeth/SimpleSerialize.swift) | Swift implementation maintained SSZ |
| C# | [ https://github.com/codingupastorm/csharp-ssz ](https://github.com/codingupastorm/csharp-ssz) | C# implementation maintained SSZ |
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

View File

@ -34,7 +34,7 @@ __NOTICE__: This document is a work-in-progress for researchers and implementers
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Exits](#exits)
- [Voluntary exits](#voluntary-exits)
- [Attestations](#attestations-1)
- [Attestation data](#attestation-data)
- [Slot](#slot-1)
@ -118,7 +118,7 @@ Once a validator has been processed and added to the beacon state's `validator_r
### Activation
In normal operation, the validator is quickly activated at which point the validator is added to the shuffling and begins validation after an additional `ENTRY_EXIT_DELAY` epochs (25.6 minutes).
In normal operation, the validator is quickly activated at which point the validator is added to the shuffling and begins validation after an additional `ACTIVATION_EXIT_DELAY` epochs (25.6 minutes).
The function [`is_active_validator`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#is_active_validator) can be used to check if a validator is active during a given epoch. Usage is as follows:
@ -232,15 +232,15 @@ Up to `MAX_ATTESTATIONS` aggregate attestations can be included in the `block`.
Up to `MAX_DEPOSITS` [`Deposit`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#deposit) objects can be included in the `block`. These deposits are constructed from the `Deposit` logs from the [Eth1.0 deposit contract](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#ethereum-10-deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#deposits-1).
##### Exits
##### Voluntary exits
Up to `MAX_EXITS` [`Exit`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#exit) objects can be included in the `block`. The exits must satisfy the verification conditions found in [exits processing](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#exits-1).
Up to `MAX_VOLUNTARY_EXITS` [`VoluntaryExit`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#voluntaryexit) objects can be included in the `block`. The exits must satisfy the verification conditions found in [exits processing](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#exits-1).
### Attestations
A validator is expected to create, sign, and broadcast an attestation during each epoch. The slot during which the validator performs this role is any slot at which `get_crosslink_committees_at_slot(state, slot)` contains a committee that contains `validator_index`.
A validator should create and broadcast the attestation halfway through the `slot` during which the validator is assigned -- that is `SLOT_DURATION * 0.5` seconds after the start of `slot`.
A validator should create and broadcast the attestation halfway through the `slot` during which the validator is assigned -- that is `SECONDS_PER_SLOT * 0.5` seconds after the start of `slot`.
#### Attestation data
@ -260,9 +260,9 @@ Set `attestation_data.beacon_block_root = hash_tree_root(head)` where `head` is
##### Epoch boundary root
Set `attestation_data.epoch_boundary_root = hash_tree_root(epoch_boundary)` where `epoch_boundary` is the block at the most recent epoch boundary in the chain defined by `head` -- i.e. the `BeaconBlock` where `block.slot == get_epoch_start_slot(head.slot)`.
Set `attestation_data.epoch_boundary_root = hash_tree_root(epoch_boundary)` where `epoch_boundary` is the block at the most recent epoch boundary in the chain defined by `head` -- i.e. the `BeaconBlock` where `block.slot == get_epoch_start_slot(slot_to_epoch(head.slot))`.
_Note:_ This can be looked up in the state using `get_block_root(state, get_epoch_start_slot(head.slot))`.
_Note:_ This can be looked up in the state using `get_block_root(state, get_epoch_start_slot(slot_to_epoch(head.slot)))`.
##### Shard block root
@ -347,7 +347,7 @@ Either (2) or (3) occurs if (1) fails. The choice between (2) and (3) is determi
def get_next_epoch_committee_assignment(
state: BeaconState,
validator_index: ValidatorIndex,
registry_change: bool) -> Tuple[List[ValidatorIndex], ShardNumber, SlotNumber, bool]:
registry_change: bool) -> Tuple[List[ValidatorIndex], Shard, Slot, bool]:
"""
Return the committee assignment in the next epoch for ``validator_index`` and ``registry_change``.
``assignment`` returned is a tuple of the following form:
@ -360,14 +360,14 @@ def get_next_epoch_committee_assignment(
current_epoch = get_current_epoch(state)
next_epoch = current_epoch + 1
next_epoch_start_slot = get_epoch_start_slot(next_epoch)
for slot in range(next_epoch_start_slot, next_epoch_start_slot + EPOCH_LENGTH):
for slot in range(next_epoch_start_slot, next_epoch_start_slot + SLOTS_PER_EPOCH):
crosslink_committees = get_crosslink_committees_at_slot(
state,
slot,
registry_change=registry_change,
)
selected_committees = [
committee # Tuple[List[ValidatorIndex], ShardNumber]
committee # Tuple[List[ValidatorIndex], Shard]
for committee in crosslink_committees
if validator_index in committee[0]
]