|
|
|
@ -49,48 +49,52 @@
|
|
|
|
|
- [Beacon state](#beacon-state)
|
|
|
|
|
- [`BeaconState`](#beaconstate)
|
|
|
|
|
- [Helper functions](#helper-functions)
|
|
|
|
|
- [`xor`](#xor)
|
|
|
|
|
- [`hash`](#hash)
|
|
|
|
|
- [`hash_tree_root`](#hash_tree_root)
|
|
|
|
|
- [`signing_root`](#signing_root)
|
|
|
|
|
- [`bls_domain`](#bls_domain)
|
|
|
|
|
- [`slot_to_epoch`](#slot_to_epoch)
|
|
|
|
|
- [`get_previous_epoch`](#get_previous_epoch)
|
|
|
|
|
- [`get_current_epoch`](#get_current_epoch)
|
|
|
|
|
- [`get_epoch_start_slot`](#get_epoch_start_slot)
|
|
|
|
|
- [`is_active_validator`](#is_active_validator)
|
|
|
|
|
- [`is_slashable_validator`](#is_slashable_validator)
|
|
|
|
|
- [`get_active_validator_indices`](#get_active_validator_indices)
|
|
|
|
|
- [`increase_balance`](#increase_balance)
|
|
|
|
|
- [`decrease_balance`](#decrease_balance)
|
|
|
|
|
- [`get_epoch_committee_count`](#get_epoch_committee_count)
|
|
|
|
|
- [`get_shard_delta`](#get_shard_delta)
|
|
|
|
|
- [`get_epoch_start_shard`](#get_epoch_start_shard)
|
|
|
|
|
- [`get_attestation_data_slot`](#get_attestation_data_slot)
|
|
|
|
|
- [`get_block_root_at_slot`](#get_block_root_at_slot)
|
|
|
|
|
- [`get_block_root`](#get_block_root)
|
|
|
|
|
- [`get_randao_mix`](#get_randao_mix)
|
|
|
|
|
- [`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)
|
|
|
|
|
- [`get_shuffled_index`](#get_shuffled_index)
|
|
|
|
|
- [`compute_committee`](#compute_committee)
|
|
|
|
|
- [`get_crosslink_committee`](#get_crosslink_committee)
|
|
|
|
|
- [`get_attesting_indices`](#get_attesting_indices)
|
|
|
|
|
- [`int_to_bytes`](#int_to_bytes)
|
|
|
|
|
- [`bytes_to_int`](#bytes_to_int)
|
|
|
|
|
- [`get_total_balance`](#get_total_balance)
|
|
|
|
|
- [`get_domain`](#get_domain)
|
|
|
|
|
- [`convert_to_indexed`](#convert_to_indexed)
|
|
|
|
|
- [`validate_indexed_attestation`](#validate_indexed_attestation)
|
|
|
|
|
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
|
|
|
|
|
- [`integer_squareroot`](#integer_squareroot)
|
|
|
|
|
- [`get_delayed_activation_exit_epoch`](#get_delayed_activation_exit_epoch)
|
|
|
|
|
- [`get_churn_limit`](#get_churn_limit)
|
|
|
|
|
- [`bls_verify`](#bls_verify)
|
|
|
|
|
- [`bls_verify_multiple`](#bls_verify_multiple)
|
|
|
|
|
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
|
|
|
|
|
- [Math and crypto](#math-and-crypto)
|
|
|
|
|
- [`int_to_bytes`](#int_to_bytes)
|
|
|
|
|
- [`bytes_to_int`](#bytes_to_int)
|
|
|
|
|
- [`integer_squareroot`](#integer_squareroot)
|
|
|
|
|
- [`xor`](#xor)
|
|
|
|
|
- [`hash`](#hash)
|
|
|
|
|
- [`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)
|
|
|
|
|
- [Beacon state getters](#beacon-state-getters)
|
|
|
|
|
- [`get_current_epoch`](#get_current_epoch)
|
|
|
|
|
- [`get_previous_epoch`](#get_previous_epoch)
|
|
|
|
|
- [`get_committee_count`](#get_committee_count)
|
|
|
|
|
- [`get_start_shard`](#get_start_shard)
|
|
|
|
|
- [`get_active_validator_indices`](#get_active_validator_indices)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [`bls_domain`](#bls_domain)
|
|
|
|
|
- [`slot_to_epoch`](#slot_to_epoch)
|
|
|
|
|
- [`epoch_start_slot`](#epoch_start_slot)
|
|
|
|
|
- [`is_active_validator`](#is_active_validator)
|
|
|
|
|
- [`is_slashable_validator`](#is_slashable_validator)
|
|
|
|
|
- [`increase_balance`](#increase_balance)
|
|
|
|
|
- [`decrease_balance`](#decrease_balance)
|
|
|
|
|
- [`get_shard_delta`](#get_shard_delta)
|
|
|
|
|
- [`get_attestation_data_slot`](#get_attestation_data_slot)
|
|
|
|
|
- [`get_block_root_at_slot`](#get_block_root_at_slot)
|
|
|
|
|
- [`get_block_root`](#get_block_root)
|
|
|
|
|
- [`get_randao_mix`](#get_randao_mix)
|
|
|
|
|
- [`get_compact_committees_root`](#get_compact_committees_root)
|
|
|
|
|
- [`get_seed`](#get_seed)
|
|
|
|
|
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
|
|
|
|
|
- [`verify_merkle_branch`](#verify_merkle_branch)
|
|
|
|
|
- [`get_shuffled_index`](#get_shuffled_index)
|
|
|
|
|
- [`compute_committee`](#compute_committee)
|
|
|
|
|
- [`get_crosslink_committee`](#get_crosslink_committee)
|
|
|
|
|
- [`get_attesting_indices`](#get_attesting_indices)
|
|
|
|
|
- [`get_total_balance`](#get_total_balance)
|
|
|
|
|
- [`get_domain`](#get_domain)
|
|
|
|
|
- [`get_indexed_attestation`](#get_indexed_attestation)
|
|
|
|
|
- [`validate_indexed_attestation`](#validate_indexed_attestation)
|
|
|
|
|
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
|
|
|
|
|
- [`get_delayed_activation_exit_epoch`](#get_delayed_activation_exit_epoch)
|
|
|
|
|
- [`get_churn_limit`](#get_churn_limit)
|
|
|
|
|
- [Routines for updating validator status](#routines-for-updating-validator-status)
|
|
|
|
|
- [`initiate_validator_exit`](#initiate_validator_exit)
|
|
|
|
|
- [`slash_validator`](#slash_validator)
|
|
|
|
@ -547,133 +551,154 @@ class BeaconState(Container):
|
|
|
|
|
|
|
|
|
|
*Note*: The definitions below are for specification purposes and are not necessarily optimal implementations.
|
|
|
|
|
|
|
|
|
|
### `xor`
|
|
|
|
|
### Math
|
|
|
|
|
|
|
|
|
|
#### `int_to_bytes`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def int_to_bytes(integer: int, length: int) -> bytes:
|
|
|
|
|
return integer.to_bytes(length, 'little')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `bytes_to_int`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def bytes_to_int(data: bytes) -> int:
|
|
|
|
|
return int.from_bytes(data, 'little')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `integer_squareroot`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def integer_squareroot(n: int) -> int:
|
|
|
|
|
"""
|
|
|
|
|
Return the largest integer ``x`` such that ``x**2 <= n``.
|
|
|
|
|
"""
|
|
|
|
|
assert n >= 0
|
|
|
|
|
x = n
|
|
|
|
|
y = (x + 1) // 2
|
|
|
|
|
while y < x:
|
|
|
|
|
x = y
|
|
|
|
|
y = (x + n // x) // 2
|
|
|
|
|
return x
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `xor`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32:
|
|
|
|
|
"""
|
|
|
|
|
Return the exclusive or of two 32-byte strings.
|
|
|
|
|
"""
|
|
|
|
|
return Bytes32(a ^ b for a, b in zip(bytes1, bytes2))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `hash`
|
|
|
|
|
### Crypto
|
|
|
|
|
|
|
|
|
|
#### `hash`
|
|
|
|
|
|
|
|
|
|
The `hash` function is SHA256.
|
|
|
|
|
|
|
|
|
|
*Note*: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethereum 2.0 deployment phase.
|
|
|
|
|
#### `hash_tree_root`
|
|
|
|
|
|
|
|
|
|
### `hash_tree_root`
|
|
|
|
|
`def hash_tree_root(object: SSZSerializable) -> Hash` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the [SSZ spec](../simple-serialize.md#merkleization).
|
|
|
|
|
|
|
|
|
|
`def hash_tree_root(object: SSZSerializable) -> Hash` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the [SimpleSerialize spec](../simple-serialize.md#merkleization).
|
|
|
|
|
#### `signing_root`
|
|
|
|
|
|
|
|
|
|
### `signing_root`
|
|
|
|
|
`def signing_root(object: Container) -> Hash` is a function for computing signing messages, as defined in the [SSZ spec](../simple-serialize.md#self-signed-containers).
|
|
|
|
|
|
|
|
|
|
`def signing_root(object: Container) -> Hash` is a function for computing signing messages, as defined in the [SimpleSerialize spec](../simple-serialize.md#self-signed-containers).
|
|
|
|
|
#### `bls_verify`
|
|
|
|
|
|
|
|
|
|
### `bls_domain`
|
|
|
|
|
`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).
|
|
|
|
|
|
|
|
|
|
### Beacon state getters
|
|
|
|
|
|
|
|
|
|
#### `get_current_epoch`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def bls_domain(domain_type: int, fork_version: bytes=b'\x00\x00\x00\x00') -> int:
|
|
|
|
|
def get_current_epoch(state: BeaconState) -> Epoch:
|
|
|
|
|
"""
|
|
|
|
|
Return the bls domain given by the ``domain_type`` and optional 4 byte ``fork_version`` (defaults to zero).
|
|
|
|
|
Return the current epoch.
|
|
|
|
|
"""
|
|
|
|
|
return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
|
|
|
|
|
return slot_to_epoch(state.slot)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `slot_to_epoch`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def slot_to_epoch(slot: Slot) -> Epoch:
|
|
|
|
|
"""
|
|
|
|
|
Return the epoch number of the given ``slot``.
|
|
|
|
|
"""
|
|
|
|
|
return Epoch(slot // SLOTS_PER_EPOCH)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_previous_epoch`
|
|
|
|
|
#### `get_previous_epoch`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_previous_epoch(state: BeaconState) -> Epoch:
|
|
|
|
|
"""`
|
|
|
|
|
Return the previous epoch of the given ``state``.
|
|
|
|
|
Return the current epoch if it's genesis epoch.
|
|
|
|
|
Return the previous epoch (current epoch if at ``GENESIS_EPOCH``).
|
|
|
|
|
"""
|
|
|
|
|
current_epoch = get_current_epoch(state)
|
|
|
|
|
return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_current_epoch`
|
|
|
|
|
#### `get_block_root`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_current_epoch(state: BeaconState) -> Epoch:
|
|
|
|
|
def get_block_root(state: BeaconState, epoch: Epoch) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the current epoch of the given ``state``.
|
|
|
|
|
Return the block root at a recent ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return slot_to_epoch(state.slot)
|
|
|
|
|
return get_block_root_at_slot(state, epoch_start_slot(epoch))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_epoch_start_slot`
|
|
|
|
|
#### `get_block_root_at_slot`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_epoch_start_slot(epoch: Epoch) -> Slot:
|
|
|
|
|
def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the starting slot of the given ``epoch``.
|
|
|
|
|
Return the block root at a recent ``slot``.
|
|
|
|
|
"""
|
|
|
|
|
return Slot(epoch * SLOTS_PER_EPOCH)
|
|
|
|
|
assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
|
|
|
|
|
return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `is_active_validator`
|
|
|
|
|
#### `get_randao_mix`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
|
|
|
|
|
def get_randao_mix(state: BeaconState, epoch: Epoch) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Check if ``validator`` is active.
|
|
|
|
|
Return the randao mix at a recent ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return validator.activation_epoch <= epoch < validator.exit_epoch
|
|
|
|
|
return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `is_slashable_validator`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Check if ``validator`` is slashable.
|
|
|
|
|
"""
|
|
|
|
|
return (not validator.slashed) and (validator.activation_epoch <= epoch < validator.withdrawable_epoch)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_active_validator_indices`
|
|
|
|
|
#### `get_active_validator_indices`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> Sequence[ValidatorIndex]:
|
|
|
|
|
"""
|
|
|
|
|
Get active validator indices at ``epoch``.
|
|
|
|
|
Return the sequence of active validator indices at ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return [ValidatorIndex(i) for i, v in enumerate(state.validators) if is_active_validator(v, epoch)]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `increase_balance`
|
|
|
|
|
#### `get_churn_limit`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
|
|
|
|
def get_churn_limit(state: BeaconState) -> int:
|
|
|
|
|
"""
|
|
|
|
|
Increase validator balance by ``delta``.
|
|
|
|
|
Return the validator churn limit for the current epoch.
|
|
|
|
|
"""
|
|
|
|
|
state.balances[index] += delta
|
|
|
|
|
active_validator_indices = get_active_validator_indices(state, get_current_epoch(state))
|
|
|
|
|
return max(MIN_PER_EPOCH_CHURN_LIMIT, len(active_validator_indices) // CHURN_LIMIT_QUOTIENT)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `decrease_balance`
|
|
|
|
|
|
|
|
|
|
#### `get_committee_count`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Decrease validator balance by ``delta`` with underflow protection.
|
|
|
|
|
"""
|
|
|
|
|
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_epoch_committee_count`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int:
|
|
|
|
|
def get_committee_count(state: BeaconState, epoch: Epoch) -> int:
|
|
|
|
|
"""
|
|
|
|
|
Return the number of committees at ``epoch``.
|
|
|
|
|
"""
|
|
|
|
@ -687,22 +712,41 @@ def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int:
|
|
|
|
|
) * SLOTS_PER_EPOCH
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_shard_delta`
|
|
|
|
|
#### `get_seed`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:
|
|
|
|
|
def get_seed(state: BeaconState, epoch: Epoch) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the number of shards to increment ``state.start_shard`` during ``epoch``.
|
|
|
|
|
Return the seed at ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH)
|
|
|
|
|
return hash(
|
|
|
|
|
get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + # Avoid underflow
|
|
|
|
|
hash_tree_root(List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, epoch))) +
|
|
|
|
|
int_to_bytes(epoch, length=32)
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_epoch_start_shard`
|
|
|
|
|
#### `get_crosslink_committee`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
|
|
|
|
|
def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> Sequence[ValidatorIndex]:
|
|
|
|
|
"""
|
|
|
|
|
Return the start shard of the 0th committee in an epoch.
|
|
|
|
|
Return the crosslink committee at ``epoch`` for ``shard``.
|
|
|
|
|
"""
|
|
|
|
|
return compute_committee(
|
|
|
|
|
indices=get_active_validator_indices(state, epoch),
|
|
|
|
|
seed=get_seed(state, epoch),
|
|
|
|
|
index=(shard + SHARD_COUNT - get_start_shard(state, epoch)) % SHARD_COUNT,
|
|
|
|
|
count=get_committee_count(state, epoch),
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `get_start_shard`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
|
|
|
|
|
"""
|
|
|
|
|
Return the start shard of the 0th committee at ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
assert epoch <= get_current_epoch(state) + 1
|
|
|
|
|
check_epoch = Epoch(get_current_epoch(state) + 1)
|
|
|
|
@ -713,60 +757,62 @@ def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
|
|
|
|
|
return shard
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_attestation_data_slot`
|
|
|
|
|
#### `get_shard_delta`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_shard_delta(state: BeaconState, epoch: Epoch) -> Shard:
|
|
|
|
|
"""
|
|
|
|
|
Return the number of shards to increment ``state.start_shard`` at ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return Shard(min(get_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `get_beacon_proposer_index`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
|
|
|
|
|
"""
|
|
|
|
|
Return the beacon proposer index at the current epoch.
|
|
|
|
|
"""
|
|
|
|
|
epoch = get_current_epoch(state)
|
|
|
|
|
committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH
|
|
|
|
|
offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH)
|
|
|
|
|
shard = Shard((get_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
|
|
|
|
first_committee = get_crosslink_committee(state, epoch, shard)
|
|
|
|
|
MAX_RANDOM_BYTE = 2**8 - 1
|
|
|
|
|
seed = get_seed(state, epoch)
|
|
|
|
|
i = 0
|
|
|
|
|
while True:
|
|
|
|
|
candidate_index = first_committee[(epoch + i) % len(first_committee)]
|
|
|
|
|
random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
|
|
|
|
|
effective_balance = state.validators[candidate_index].effective_balance
|
|
|
|
|
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
|
|
|
|
return ValidatorIndex(candidate_index)
|
|
|
|
|
i += 1
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `get_attestation_data_slot`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot:
|
|
|
|
|
committee_count = get_epoch_committee_count(state, data.target.epoch)
|
|
|
|
|
offset = (data.crosslink.shard + SHARD_COUNT - get_epoch_start_shard(state, data.target.epoch)) % SHARD_COUNT
|
|
|
|
|
return Slot(get_epoch_start_slot(data.target.epoch) + offset // (committee_count // SLOTS_PER_EPOCH))
|
|
|
|
|
"""
|
|
|
|
|
Return the slot corresponding to the attestation ``data``.
|
|
|
|
|
"""
|
|
|
|
|
committee_count = get_committee_count(state, data.target.epoch)
|
|
|
|
|
offset = (data.crosslink.shard + SHARD_COUNT - get_start_shard(state, data.target.epoch)) % SHARD_COUNT
|
|
|
|
|
return Slot(epoch_start_slot(data.target.epoch) + offset // (committee_count // SLOTS_PER_EPOCH))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_block_root_at_slot`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_block_root_at_slot(state: BeaconState,
|
|
|
|
|
slot: Slot) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the block root at a recent ``slot``.
|
|
|
|
|
"""
|
|
|
|
|
assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
|
|
|
|
|
return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_block_root`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_block_root(state: BeaconState,
|
|
|
|
|
epoch: Epoch) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the block root at a recent ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return get_block_root_at_slot(state, get_epoch_start_slot(epoch))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_randao_mix`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_randao_mix(state: BeaconState,
|
|
|
|
|
epoch: Epoch) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the randao mix at a recent ``epoch``.
|
|
|
|
|
``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch].
|
|
|
|
|
"""
|
|
|
|
|
return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_compact_committees_root`
|
|
|
|
|
#### `get_compact_committees_root`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash:
|
|
|
|
|
"""
|
|
|
|
|
Return the compact committee root for the current epoch.
|
|
|
|
|
Return the compact committee root at ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
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)):
|
|
|
|
|
start_shard = get_start_shard(state, epoch)
|
|
|
|
|
for committee_number in range(get_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]
|
|
|
|
@ -778,63 +824,159 @@ def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash:
|
|
|
|
|
return hash_tree_root(Vector[CompactCommittee, SHARD_COUNT](committees))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `generate_seed`
|
|
|
|
|
#### `get_total_balance`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def generate_seed(state: BeaconState,
|
|
|
|
|
epoch: Epoch) -> Hash:
|
|
|
|
|
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
|
|
|
|
|
"""
|
|
|
|
|
Generate a seed for the given ``epoch``.
|
|
|
|
|
Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
|
|
|
|
|
"""
|
|
|
|
|
return hash(
|
|
|
|
|
get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + # Avoid underflow
|
|
|
|
|
hash_tree_root(List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, epoch))) +
|
|
|
|
|
int_to_bytes(epoch, length=32)
|
|
|
|
|
return Gwei(max(sum([state.validators[index].effective_balance for index in indices]), 1))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `get_domain`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_domain(state: BeaconState, domain_type: int, message_epoch: Epoch=None) -> int:
|
|
|
|
|
"""
|
|
|
|
|
Return the signature domain (fork version concatenated with domain type) of a message.
|
|
|
|
|
"""
|
|
|
|
|
epoch = get_current_epoch(state) if message_epoch is None else message_epoch
|
|
|
|
|
fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
|
|
|
|
|
return bls_domain(domain_type, fork_version)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `get_indexed_attestation`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> IndexedAttestation:
|
|
|
|
|
"""
|
|
|
|
|
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),
|
|
|
|
|
data=attestation.data,
|
|
|
|
|
signature=attestation.signature,
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_beacon_proposer_index`
|
|
|
|
|
#### `get_attesting_indices`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
|
|
|
|
|
def get_attesting_indices(state: BeaconState,
|
|
|
|
|
data: AttestationData,
|
|
|
|
|
bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]) -> Set[ValidatorIndex]:
|
|
|
|
|
"""
|
|
|
|
|
Return the current beacon proposer index.
|
|
|
|
|
Return the set of attesting indices corresponding to ``data`` and ``bits``.
|
|
|
|
|
"""
|
|
|
|
|
epoch = get_current_epoch(state)
|
|
|
|
|
committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH
|
|
|
|
|
offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH)
|
|
|
|
|
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
|
|
|
|
first_committee = get_crosslink_committee(state, epoch, shard)
|
|
|
|
|
MAX_RANDOM_BYTE = 2**8 - 1
|
|
|
|
|
seed = generate_seed(state, epoch)
|
|
|
|
|
i = 0
|
|
|
|
|
while True:
|
|
|
|
|
candidate_index = first_committee[(epoch + i) % len(first_committee)]
|
|
|
|
|
random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
|
|
|
|
|
effective_balance = state.validators[candidate_index].effective_balance
|
|
|
|
|
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
|
|
|
|
return ValidatorIndex(candidate_index)
|
|
|
|
|
i += 1
|
|
|
|
|
committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard)
|
|
|
|
|
return set(index for i, index in enumerate(committee) if bits[i])
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `verify_merkle_branch`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### `verify_merkle_branch`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def verify_merkle_branch(leaf: Hash, proof: Sequence[Hash], depth: int, index: int, root: Hash) -> bool:
|
|
|
|
|
def verify_merkle_branch(leaf: Hash, branch: Sequence[Hash], depth: int, index: int, root: Hash) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Verify that the given ``leaf`` is on the merkle branch ``proof``
|
|
|
|
|
starting with the given ``root``.
|
|
|
|
|
Verify that the ``leaf`` at ``index`` verifies against ``root`` on the Merkle ``branch``.
|
|
|
|
|
"""
|
|
|
|
|
value = leaf
|
|
|
|
|
for i in range(depth):
|
|
|
|
|
if index // (2**i) % 2:
|
|
|
|
|
value = hash(proof[i] + value)
|
|
|
|
|
value = hash(branch[i] + value)
|
|
|
|
|
else:
|
|
|
|
|
value = hash(value + proof[i])
|
|
|
|
|
value = hash(value + branch[i])
|
|
|
|
|
return value == root
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_shuffled_index`
|
|
|
|
|
|
|
|
|
|
#### `bls_domain`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def bls_domain(domain_type: int, fork_version: bytes=b'\x00\x00\x00\x00') -> int:
|
|
|
|
|
"""
|
|
|
|
|
Return the bls domain given by the ``domain_type`` and optional 4 byte ``fork_version`` (defaults to zero).
|
|
|
|
|
"""
|
|
|
|
|
return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `slot_to_epoch`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def slot_to_epoch(slot: Slot) -> Epoch:
|
|
|
|
|
"""
|
|
|
|
|
Return the epoch number of the given ``slot``.
|
|
|
|
|
"""
|
|
|
|
|
return Epoch(slot // SLOTS_PER_EPOCH)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `epoch_start_slot`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def epoch_start_slot(epoch: Epoch) -> Slot:
|
|
|
|
|
"""
|
|
|
|
|
Return the starting slot of the given ``epoch``.
|
|
|
|
|
"""
|
|
|
|
|
return Slot(epoch * SLOTS_PER_EPOCH)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `is_active_validator`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Check if ``validator`` is active.
|
|
|
|
|
"""
|
|
|
|
|
return validator.activation_epoch <= epoch < validator.exit_epoch
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `is_slashable_validator`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Check if ``validator`` is slashable.
|
|
|
|
|
"""
|
|
|
|
|
return (not validator.slashed) and (validator.activation_epoch <= epoch < validator.withdrawable_epoch)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `increase_balance`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Increase validator balance by ``delta``.
|
|
|
|
|
"""
|
|
|
|
|
state.balances[index] += delta
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `decrease_balance`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Decrease validator balance by ``delta`` with underflow protection.
|
|
|
|
|
"""
|
|
|
|
|
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### `get_shuffled_index`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Hash) -> ValidatorIndex:
|
|
|
|
@ -861,7 +1003,7 @@ def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Hash) -> V
|
|
|
|
|
return ValidatorIndex(index)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `compute_committee`
|
|
|
|
|
#### `compute_committee`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def compute_committee(indices: Sequence[ValidatorIndex],
|
|
|
|
@ -871,90 +1013,7 @@ def compute_committee(indices: Sequence[ValidatorIndex],
|
|
|
|
|
return [indices[get_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_crosslink_committee`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> Sequence[ValidatorIndex]:
|
|
|
|
|
return compute_committee(
|
|
|
|
|
indices=get_active_validator_indices(state, epoch),
|
|
|
|
|
seed=generate_seed(state, epoch),
|
|
|
|
|
index=(shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) % SHARD_COUNT,
|
|
|
|
|
count=get_epoch_committee_count(state, epoch),
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_attesting_indices`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_attesting_indices(state: BeaconState,
|
|
|
|
|
data: AttestationData,
|
|
|
|
|
bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]) -> Set[ValidatorIndex]:
|
|
|
|
|
"""
|
|
|
|
|
Return the set of attesting indices corresponding to ``data`` and ``bitfield``.
|
|
|
|
|
"""
|
|
|
|
|
committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard)
|
|
|
|
|
return set(index for i, index in enumerate(committee) if bits[i])
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `int_to_bytes`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def int_to_bytes(integer: int, length: int) -> bytes:
|
|
|
|
|
return integer.to_bytes(length, 'little')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `bytes_to_int`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def bytes_to_int(data: bytes) -> int:
|
|
|
|
|
return int.from_bytes(data, 'little')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_total_balance`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
|
|
|
|
|
"""
|
|
|
|
|
Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
|
|
|
|
|
"""
|
|
|
|
|
return Gwei(max(sum([state.validators[index].effective_balance for index in indices]), 1))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_domain`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_domain(state: BeaconState,
|
|
|
|
|
domain_type: int,
|
|
|
|
|
message_epoch: Epoch=None) -> int:
|
|
|
|
|
"""
|
|
|
|
|
Return the signature domain (fork version concatenated with domain type) of a message.
|
|
|
|
|
"""
|
|
|
|
|
epoch = get_current_epoch(state) if message_epoch is None else message_epoch
|
|
|
|
|
fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
|
|
|
|
|
return bls_domain(domain_type, fork_version)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `convert_to_indexed`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def convert_to_indexed(state: BeaconState, attestation: Attestation) -> IndexedAttestation:
|
|
|
|
|
"""
|
|
|
|
|
Convert ``attestation`` to (almost) indexed-verifiable form.
|
|
|
|
|
"""
|
|
|
|
|
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),
|
|
|
|
|
data=attestation.data,
|
|
|
|
|
signature=attestation.signature,
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `validate_indexed_attestation`
|
|
|
|
|
#### `validate_indexed_attestation`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def validate_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> None:
|
|
|
|
@ -987,7 +1046,7 @@ def validate_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `is_slashable_attestation_data`
|
|
|
|
|
#### `is_slashable_attestation_data`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
|
|
|
|
@ -1002,23 +1061,7 @@ def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationDa
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `integer_squareroot`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def integer_squareroot(n: int) -> int:
|
|
|
|
|
"""
|
|
|
|
|
The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``.
|
|
|
|
|
"""
|
|
|
|
|
assert n >= 0
|
|
|
|
|
x = n
|
|
|
|
|
y = (x + 1) // 2
|
|
|
|
|
while y < x:
|
|
|
|
|
x = y
|
|
|
|
|
y = (x + n // x) // 2
|
|
|
|
|
return x
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_delayed_activation_exit_epoch`
|
|
|
|
|
#### `get_delayed_activation_exit_epoch`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
|
|
|
|
@ -1028,31 +1071,6 @@ def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
|
|
|
|
|
return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `get_churn_limit`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_churn_limit(state: BeaconState) -> int:
|
|
|
|
|
"""
|
|
|
|
|
Return the churn limit based on the active validator count.
|
|
|
|
|
"""
|
|
|
|
|
return max(
|
|
|
|
|
MIN_PER_EPOCH_CHURN_LIMIT,
|
|
|
|
|
len(get_active_validator_indices(state, get_current_epoch(state))) // CHURN_LIMIT_QUOTIENT
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### `bls_verify`
|
|
|
|
|
|
|
|
|
|
`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).
|
|
|
|
|
|
|
|
|
|
### Routines for updating validator status
|
|
|
|
|
|
|
|
|
|
*Note*: All functions in this section mutate `state`.
|
|
|
|
@ -1340,8 +1358,8 @@ def process_justification_and_finalization(state: BeaconState) -> None:
|
|
|
|
|
def process_crosslinks(state: BeaconState) -> None:
|
|
|
|
|
state.previous_crosslinks = [c for c in state.current_crosslinks]
|
|
|
|
|
for epoch in (get_previous_epoch(state), get_current_epoch(state)):
|
|
|
|
|
for offset in range(get_epoch_committee_count(state, epoch)):
|
|
|
|
|
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
|
|
|
|
for offset in range(get_committee_count(state, epoch)):
|
|
|
|
|
shard = Shard((get_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
|
|
|
|
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
|
|
|
|
|
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
|
|
|
|
|
if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee):
|
|
|
|
@ -1413,8 +1431,8 @@ def get_crosslink_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[G
|
|
|
|
|
rewards = [Gwei(0) for _ in range(len(state.validators))]
|
|
|
|
|
penalties = [Gwei(0) for _ in range(len(state.validators))]
|
|
|
|
|
epoch = get_previous_epoch(state)
|
|
|
|
|
for offset in range(get_epoch_committee_count(state, epoch)):
|
|
|
|
|
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
|
|
|
|
for offset in range(get_committee_count(state, epoch)):
|
|
|
|
|
shard = Shard((get_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
|
|
|
|
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
|
|
|
|
|
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
|
|
|
|
|
attesting_balance = get_total_balance(state, attesting_indices)
|
|
|
|
@ -1674,7 +1692,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
|
|
|
|
assert data.crosslink.data_root == ZERO_HASH # [to be removed in phase 1]
|
|
|
|
|
|
|
|
|
|
# Check signature
|
|
|
|
|
validate_indexed_attestation(state, convert_to_indexed(state, attestation))
|
|
|
|
|
validate_indexed_attestation(state, get_indexed_attestation(state, attestation))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
##### Deposits
|
|
|
|
@ -1687,7 +1705,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
|
|
|
|
# Verify the Merkle branch
|
|
|
|
|
assert verify_merkle_branch(
|
|
|
|
|
leaf=hash_tree_root(deposit.data),
|
|
|
|
|
proof=deposit.proof,
|
|
|
|
|
branch=deposit.proof,
|
|
|
|
|
depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # add 1 for the SSZ length mix-in
|
|
|
|
|
index=state.eth1_deposit_index,
|
|
|
|
|
root=state.eth1_data.deposit_root,
|
|
|
|
|