This commit is contained in:
Justin Drake 2019-06-30 10:02:18 +01:00
parent 2f43f9c339
commit d0acd81157
12 changed files with 373 additions and 355 deletions

View File

@ -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,

View File

@ -124,7 +124,7 @@ def get_latest_attesting_balance(store: Store, root: Hash) -> Gwei:
def get_head(store: Store) -> Hash:
# Execute the LMD-GHOST fork choice
head = store.justified_checkpoint.root
justified_slot = get_epoch_start_slot(store.justified_checkpoint.epoch)
justified_slot = epoch_start_slot(store.justified_checkpoint.epoch)
while True:
children = [
root for root in store.blocks.keys()
@ -162,7 +162,7 @@ def on_block(store: Store, block: BeaconBlock) -> None:
store.finalized_checkpoint.root
)
# Check that block is later than the finalized epoch slot
assert block.slot > get_epoch_start_slot(store.finalized_checkpoint.epoch)
assert block.slot > epoch_start_slot(store.finalized_checkpoint.epoch)
# Check the block is valid and compute the post-state
state = state_transition(pre_state, block)
# Add new state for this block to the store
@ -190,11 +190,11 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrivesr
base_state = store.block_states[target.root].copy()
assert store.time >= base_state.genesis_time + get_epoch_start_slot(target.epoch) * SECONDS_PER_SLOT
assert store.time >= base_state.genesis_time + epoch_start_slot(target.epoch) * SECONDS_PER_SLOT
# Store target checkpoint state if not yet seen
if target not in store.checkpoint_states:
process_slots(base_state, get_epoch_start_slot(target.epoch))
process_slots(base_state, epoch_start_slot(target.epoch))
store.checkpoint_states[target] = base_state
target_state = store.checkpoint_states[target]
@ -204,7 +204,7 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
assert store.time >= (attestation_slot + 1) * SECONDS_PER_SLOT
# Get state at the `target` to validate attestation and calculate the committees
indexed_attestation = convert_to_indexed(target_state, attestation)
indexed_attestation = get_indexed_attestation(target_state, attestation)
validate_indexed_attestation(target_state, indexed_attestation)
# Update latest messages

View File

@ -473,7 +473,7 @@ For each `challenge` in `block.body.custody_chunk_challenges`, run the following
```python
def process_chunk_challenge(state: BeaconState, challenge: CustodyChunkChallenge) -> None:
# Verify the attestation
validate_indexed_attestation(state, convert_to_indexed(state, challenge.attestation))
validate_indexed_attestation(state, get_indexed_attestation(state, challenge.attestation))
# Verify it is not too late to challenge
assert slot_to_epoch(challenge.attestation.data.slot) >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
responder = state.validators[challenge.responder_index]
@ -526,7 +526,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) ->
# Verify challenger is slashable
assert is_slashable_validator(challenger, get_current_epoch(state))
# Verify attestation
validate_indexed_attestation(state, convert_to_indexed(state, attestation))
validate_indexed_attestation(state, get_indexed_attestation(state, attestation))
# Verify attestation is eligible for challenging
responder = state.validators[challenge.responder_index]
assert epoch + responder.max_reveal_lateness <= get_reveal_period(state, challenge.responder_index)
@ -601,7 +601,7 @@ def process_chunk_challenge_response(state: BeaconState,
# Verify the chunk matches the crosslink data root
assert verify_merkle_branch(
leaf=hash_tree_root(response.chunk),
proof=response.data_branch,
branch=response.data_branch,
depth=challenge.depth,
index=response.chunk_index,
root=challenge.data_root,
@ -626,7 +626,7 @@ def process_bit_challenge_response(state: BeaconState,
# Verify the chunk matches the crosslink data root
assert verify_merkle_branch(
leaf=hash_tree_root(response.chunk),
proof=response.data_branch,
branch=response.data_branch,
depth=ceillog2(challenge.chunk_count),
index=response.chunk_index,
root=challenge.data_root,
@ -634,7 +634,7 @@ def process_bit_challenge_response(state: BeaconState,
# Verify the chunk bit leaf matches the challenge data
assert verify_merkle_branch(
leaf=response.chunk_bits_leaf,
proof=response.chunk_bits_branch,
branch=response.chunk_bits_branch,
depth=ceillog2(challenge.chunk_count) >> 8,
index=response.chunk_index // 256,
root=challenge.chunk_bits_merkle_root

View File

@ -139,7 +139,7 @@ def get_period_committee(state: BeaconState,
"""
return compute_committee(
indices=get_active_validator_indices(state, epoch),
seed=generate_seed(state, epoch),
seed=get_seed(state, epoch),
index=shard * count + index,
count=SHARD_COUNT * count,
)
@ -150,7 +150,7 @@ def get_period_committee(state: BeaconState,
```python
def get_switchover_epoch(state: BeaconState, epoch: Epoch, index: ValidatorIndex) -> int:
earlier_start_epoch = Epoch(epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2)
return (bytes_to_int(hash(generate_seed(state, earlier_start_epoch) + int_to_bytes(index, length=3)[0:8]))
return (bytes_to_int(hash(get_seed(state, earlier_start_epoch) + int_to_bytes(index, length=3)[0:8]))
% PERSISTENT_COMMITTEE_PERIOD)
```

View File

@ -84,7 +84,7 @@ def get_period_data(block: ExtendedBeaconBlock, shard_id: Shard, later: bool) ->
indices = get_period_committee(block.state, shard_id, period_start, 0, committee_count)
return PeriodData(
validator_count,
generate_seed(block.state, period_start),
get_seed(block.state, period_start),
[block.state.validators[i] for i in indices],
)
```

View File

@ -145,11 +145,11 @@ def get_committee_assignment(
next_epoch = get_current_epoch(state) + 1
assert epoch <= next_epoch
committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH
epoch_start_slot = get_epoch_start_slot(epoch)
for slot in range(epoch_start_slot, epoch_start_slot + SLOTS_PER_EPOCH):
committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH
start_slot = epoch_start_slot(epoch)
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
slot_start_shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT
for i in range(committees_per_slot):
shard = (slot_start_shard + i) % SHARD_COUNT
committee = get_crosslink_committee(state, epoch, shard)
@ -307,8 +307,8 @@ Set `attestation_data.beacon_block_root = signing_root(head_block)`.
* Set `attestation_data.target_root = epoch_boundary_block_root` where `epoch_boundary_block_root` is the root of block at the most recent epoch boundary.
*Note*: `epoch_boundary_block_root` can be looked up in the state using:
* Let `epoch_start_slot = get_epoch_start_slot(get_current_epoch(head_state))`.
* Let `epoch_boundary_block_root = signing_root(head_block) if epoch_start_slot == head_state.slot else get_block_root(state, epoch_start_slot)`.
* Let `start_slot = epoch_start_slot(get_current_epoch(head_state))`.
* Let `epoch_boundary_block_root = signing_root(head_block) if start_slot == head_state.slot else get_block_root(state, start_slot)`.
##### Crosslink vote

View File

@ -14,7 +14,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
else:
assert False
indexed_attestation = spec.convert_to_indexed(state, attestation)
indexed_attestation = spec.get_indexed_attestation(state, attestation)
spec.on_attestation(store, attestation)
assert (
store.latest_messages[indexed_attestation.custody_bit_0_indices[0]] ==

View File

@ -15,7 +15,7 @@ def build_attestation_data(spec, state, slot, shard):
else:
block_root = spec.get_block_root_at_slot(state, slot)
current_epoch_start_slot = spec.get_epoch_start_slot(spec.get_current_epoch(state))
current_epoch_start_slot = spec.epoch_start_slot(spec.get_current_epoch(state))
if slot < current_epoch_start_slot:
epoch_boundary_root = spec.get_block_root(state, spec.get_previous_epoch(state))
elif slot == current_epoch_start_slot:
@ -54,8 +54,8 @@ def get_valid_attestation(spec, state, slot=None, signed=False):
slot = state.slot
epoch = spec.slot_to_epoch(slot)
epoch_start_shard = spec.get_epoch_start_shard(state, epoch)
committees_per_slot = spec.get_epoch_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
epoch_start_shard = spec.get_start_shard(state, epoch)
committees_per_slot = spec.get_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT
attestation_data = build_attestation_data(spec, state, slot, shard)

View File

@ -13,6 +13,6 @@ def get_valid_attester_slashing(spec, state, signed_1=False, signed_2=False):
sign_attestation(spec, state, attestation_2)
return spec.AttesterSlashing(
attestation_1=spec.convert_to_indexed(state, attestation_1),
attestation_2=spec.convert_to_indexed(state, attestation_2),
attestation_1=spec.get_indexed_attestation(state, attestation_1),
attestation_2=spec.get_indexed_attestation(state, attestation_2),
)

View File

@ -83,7 +83,7 @@ def test_single_crosslink_update_from_previous_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_double_late_crosslink(spec, state):
if spec.get_epoch_committee_count(state, spec.get_current_epoch(state)) < spec.SHARD_COUNT:
if spec.get_committee_count(state, spec.get_current_epoch(state)) < spec.SHARD_COUNT:
print("warning: ignoring test, test-assumptions are incompatible with configuration")
return

View File

@ -10,8 +10,8 @@ def run_process_just_and_fin(spec, state):
def get_shards_for_slot(spec, state, slot):
epoch = spec.slot_to_epoch(slot)
epoch_start_shard = spec.get_epoch_start_shard(state, epoch)
committees_per_slot = spec.get_epoch_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
epoch_start_shard = spec.get_start_shard(state, epoch)
committees_per_slot = spec.get_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT
return [shard + i for i in range(committees_per_slot)]
@ -33,8 +33,8 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
total_balance = spec.get_total_active_balance(state)
remaining_balance = total_balance * 2 // 3
epoch_start_slot = spec.get_epoch_start_slot(epoch)
for slot in range(epoch_start_slot, epoch_start_slot + spec.SLOTS_PER_EPOCH):
start_slot = spec.epoch_start_slot(epoch)
for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH):
for shard in get_shards_for_slot(spec, state, slot):
# Check if we already have had sufficient balance. (and undone if we don't want it).
# If so, do not create more attestations. (we do not have empty pending attestations normally anyway)
@ -80,7 +80,7 @@ def get_checkpoints(spec, epoch):
def put_checkpoints_in_block_roots(spec, state, checkpoints):
for c in checkpoints:
state.block_roots[spec.get_epoch_start_slot(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root
state.block_roots[spec.epoch_start_slot(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root
def finalize_on_234(spec, state, epoch, sufficient_support):

View File

@ -43,7 +43,7 @@ def next_epoch_with_attestations(spec,
block = build_empty_block_for_next_slot(spec, post_state)
if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY:
slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
if slot_to_attest >= spec.get_epoch_start_slot(spec.get_current_epoch(post_state)):
if slot_to_attest >= spec.epoch_start_slot(spec.get_current_epoch(post_state)):
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest)
block.body.attestations.append(cur_attestation)