WIP
This commit is contained in:
parent
369c457d76
commit
e8532ced79
|
@ -50,10 +50,10 @@
|
||||||
- [`BeaconState`](#beaconstate)
|
- [`BeaconState`](#beaconstate)
|
||||||
- [Helper functions](#helper-functions)
|
- [Helper functions](#helper-functions)
|
||||||
- [Math](#math)
|
- [Math](#math)
|
||||||
- [`int_to_bytes`](#int_to_bytes)
|
|
||||||
- [`bytes_to_int`](#bytes_to_int)
|
|
||||||
- [`integer_squareroot`](#integer_squareroot)
|
- [`integer_squareroot`](#integer_squareroot)
|
||||||
- [`xor`](#xor)
|
- [`xor`](#xor)
|
||||||
|
- [`int_to_bytes`](#int_to_bytes)
|
||||||
|
- [`bytes_to_int`](#bytes_to_int)
|
||||||
- [Crypto](#crypto)
|
- [Crypto](#crypto)
|
||||||
- [`hash`](#hash)
|
- [`hash`](#hash)
|
||||||
- [`hash_tree_root`](#hash_tree_root)
|
- [`hash_tree_root`](#hash_tree_root)
|
||||||
|
@ -64,42 +64,39 @@
|
||||||
- [Predicates](#predicates)
|
- [Predicates](#predicates)
|
||||||
- [`is_active_validator`](#is_active_validator)
|
- [`is_active_validator`](#is_active_validator)
|
||||||
- [`is_slashable_validator`](#is_slashable_validator)
|
- [`is_slashable_validator`](#is_slashable_validator)
|
||||||
- [`is_valid_merkle_branch`](#is_valid_merkle_branch)
|
|
||||||
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
|
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
|
||||||
|
- [`is_valid_merkle_branch`](#is_valid_merkle_branch)
|
||||||
|
- [Misc](#misc)
|
||||||
|
- [`shuffle_index`](#shuffle_index)
|
||||||
|
- [`compute_committee`](#compute_committee)
|
||||||
|
- [`validate_indexed_attestation`](#validate_indexed_attestation)
|
||||||
|
- [`slot_to_epoch`](#slot_to_epoch)
|
||||||
|
- [`epoch_first_slot`](#epoch_first_slot)
|
||||||
|
- [`delayed_activation_exit_epoch`](#delayed_activation_exit_epoch)
|
||||||
|
- [`bls_domain`](#bls_domain)
|
||||||
- [Beacon state getters](#beacon-state-getters)
|
- [Beacon state getters](#beacon-state-getters)
|
||||||
- [`get_current_epoch`](#get_current_epoch)
|
- [`get_current_epoch`](#get_current_epoch)
|
||||||
- [`get_previous_epoch`](#get_previous_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)
|
|
||||||
|
|
||||||
- [`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_block_root`](#get_block_root)
|
||||||
|
- [`get_block_root_at_slot`](#get_block_root_at_slot)
|
||||||
- [`get_randao_mix`](#get_randao_mix)
|
- [`get_randao_mix`](#get_randao_mix)
|
||||||
- [`get_compact_committees_root`](#get_compact_committees_root)
|
- [`get_active_validator_indices`](#get_active_validator_indices)
|
||||||
|
- [`get_churn_limit`](#get_churn_limit)
|
||||||
|
- [`get_committee_count`](#get_committee_count)
|
||||||
- [`get_seed`](#get_seed)
|
- [`get_seed`](#get_seed)
|
||||||
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
|
|
||||||
|
|
||||||
- [`shuffle_index`](#shuffle_index)
|
|
||||||
- [`compute_committee`](#compute_committee)
|
|
||||||
- [`get_crosslink_committee`](#get_crosslink_committee)
|
- [`get_crosslink_committee`](#get_crosslink_committee)
|
||||||
- [`get_attesting_indices`](#get_attesting_indices)
|
- [`get_start_shard`](#get_start_shard)
|
||||||
|
- [`get_shard_delta`](#get_shard_delta)
|
||||||
|
- [`get_proposer_index`](#get_proposer_index)
|
||||||
|
- [`get_attestation_data_slot`](#get_attestation_data_slot)
|
||||||
|
- [`get_compact_committees_root`](#get_compact_committees_root)
|
||||||
- [`get_total_balance`](#get_total_balance)
|
- [`get_total_balance`](#get_total_balance)
|
||||||
- [`get_domain`](#get_domain)
|
- [`get_domain`](#get_domain)
|
||||||
- [`get_indexed_attestation`](#get_indexed_attestation)
|
- [`get_indexed_attestation`](#get_indexed_attestation)
|
||||||
- [`validate_indexed_attestation`](#validate_indexed_attestation)
|
- [`get_attesting_indices`](#get_attesting_indices)
|
||||||
- [`delayed_activation_exit_epoch`](#delayed_activation_exit_epoch)
|
- [State mutators](#state-mutators)
|
||||||
- [`get_churn_limit`](#get_churn_limit)
|
- [`increase_balance`](#increase_balance)
|
||||||
- [Routines for updating validator status](#routines-for-updating-validator-status)
|
- [`decrease_balance`](#decrease_balance)
|
||||||
- [`initiate_validator_exit`](#initiate_validator_exit)
|
- [`initiate_validator_exit`](#initiate_validator_exit)
|
||||||
- [`slash_validator`](#slash_validator)
|
- [`slash_validator`](#slash_validator)
|
||||||
- [Genesis](#genesis)
|
- [Genesis](#genesis)
|
||||||
|
@ -201,6 +198,7 @@ The following values are (non-configurable) constants used throughout the specif
|
||||||
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) |
|
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) |
|
||||||
| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) |
|
| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) |
|
||||||
| `JUSTIFICATION_BITS_LENGTH` | `4` |
|
| `JUSTIFICATION_BITS_LENGTH` | `4` |
|
||||||
|
| `ENDIANNESS` | `'little'` |
|
||||||
|
|
||||||
* For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)
|
* For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)
|
||||||
|
|
||||||
|
@ -559,18 +557,6 @@ class BeaconState(Container):
|
||||||
|
|
||||||
#### `int_to_bytes`
|
#### `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`
|
#### `integer_squareroot`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -597,11 +583,29 @@ def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32:
|
||||||
return Bytes32(a ^ b for a, b in zip(bytes1, bytes2))
|
return Bytes32(a ^ b for a, b in zip(bytes1, bytes2))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
def int_to_bytes(integer: int, length: int) -> bytes:
|
||||||
|
"""
|
||||||
|
Return the ``length``-byte serialization of ``integer``.
|
||||||
|
"""
|
||||||
|
return integer.to_bytes(length, ENDIANNESS)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `bytes_to_int`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def bytes_to_int(data: bytes) -> int:
|
||||||
|
"""
|
||||||
|
Return the integer deserialization of ``data``.
|
||||||
|
"""
|
||||||
|
return int.from_bytes(data, ENDIANNESS)
|
||||||
|
```
|
||||||
|
|
||||||
### Crypto
|
### Crypto
|
||||||
|
|
||||||
#### `hash`
|
#### `hash`
|
||||||
|
|
||||||
The `hash` function is SHA256.
|
`def hash(data: bytes) -> Hash` is SHA256.
|
||||||
|
|
||||||
#### `hash_tree_root`
|
#### `hash_tree_root`
|
||||||
|
|
||||||
|
@ -625,22 +629,6 @@ The `hash` function is SHA256.
|
||||||
|
|
||||||
### Predicates
|
### Predicates
|
||||||
|
|
||||||
#### `is_valid_merkle_branch`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def is_valid_merkle_branch(leaf: Hash, branch: Sequence[Hash], depth: int, index: int, root: Hash) -> bool:
|
|
||||||
"""
|
|
||||||
Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and ``branch``.
|
|
||||||
"""
|
|
||||||
value = leaf
|
|
||||||
for i in range(depth):
|
|
||||||
if index // (2**i) % 2:
|
|
||||||
value = hash(branch[i] + value)
|
|
||||||
else:
|
|
||||||
value = hash(value + branch[i])
|
|
||||||
return value == root
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `is_active_validator`
|
#### `is_active_validator`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -676,6 +664,137 @@ def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationDa
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `is_valid_merkle_branch`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def is_valid_merkle_branch(leaf: Hash, branch: Sequence[Hash], depth: int, index: int, root: Hash) -> bool:
|
||||||
|
"""
|
||||||
|
Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and ``branch``.
|
||||||
|
"""
|
||||||
|
value = leaf
|
||||||
|
for i in range(depth):
|
||||||
|
if index // (2**i) % 2:
|
||||||
|
value = hash(branch[i] + value)
|
||||||
|
else:
|
||||||
|
value = hash(value + branch[i])
|
||||||
|
return value == root
|
||||||
|
```
|
||||||
|
|
||||||
|
### Misc
|
||||||
|
|
||||||
|
#### `shuffle_index`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def shuffle_index(index: ValidatorIndex, index_count: int, seed: Hash) -> ValidatorIndex:
|
||||||
|
"""
|
||||||
|
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
|
||||||
|
"""
|
||||||
|
assert index < index_count
|
||||||
|
assert index_count <= 2**40
|
||||||
|
|
||||||
|
# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
|
||||||
|
# See the 'generalized domain' algorithm on page 3
|
||||||
|
for current_round in range(SHUFFLE_ROUND_COUNT):
|
||||||
|
pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count
|
||||||
|
flip = ValidatorIndex((pivot + index_count - index) % index_count)
|
||||||
|
position = max(index, flip)
|
||||||
|
source = hash(
|
||||||
|
seed + int_to_bytes(current_round, length=1) +
|
||||||
|
int_to_bytes(position // 256, length=4)
|
||||||
|
)
|
||||||
|
byte = source[(position % 256) // 8]
|
||||||
|
bit = (byte >> (position % 8)) % 2
|
||||||
|
index = flip if bit else index
|
||||||
|
|
||||||
|
return ValidatorIndex(index)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `compute_committee`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def compute_committee(indices: Sequence[ValidatorIndex],
|
||||||
|
seed: Hash, index: int, count: int) -> Sequence[ValidatorIndex]:
|
||||||
|
"""
|
||||||
|
Return the committee corresponding to ``indices``, ``seed``, ``index`` and committee ``count``.
|
||||||
|
"""
|
||||||
|
start = (len(indices) * index) // count
|
||||||
|
end = (len(indices) * (index + 1)) // count
|
||||||
|
return [indices[shuffle_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `validate_indexed_attestation`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def validate_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> None:
|
||||||
|
"""
|
||||||
|
Verify validity of ``indexed_attestation``.
|
||||||
|
"""
|
||||||
|
bit_0_indices = indexed_attestation.custody_bit_0_indices
|
||||||
|
bit_1_indices = indexed_attestation.custody_bit_1_indices
|
||||||
|
|
||||||
|
# Verify no index has custody bit equal to 1 [to be removed in phase 1]
|
||||||
|
assert len(bit_1_indices) == 0
|
||||||
|
# Verify max number of indices
|
||||||
|
assert len(bit_0_indices) + len(bit_1_indices) <= MAX_VALIDATORS_PER_COMMITTEE
|
||||||
|
# Verify index sets are disjoint
|
||||||
|
assert len(set(bit_0_indices).intersection(bit_1_indices)) == 0
|
||||||
|
# Verify indices are sorted
|
||||||
|
assert bit_0_indices == sorted(bit_0_indices) and bit_1_indices == sorted(bit_1_indices)
|
||||||
|
# Verify aggregate signature
|
||||||
|
assert bls_verify_multiple(
|
||||||
|
pubkeys=[
|
||||||
|
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_0_indices]),
|
||||||
|
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_1_indices]),
|
||||||
|
],
|
||||||
|
message_hashes=[
|
||||||
|
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)),
|
||||||
|
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)),
|
||||||
|
],
|
||||||
|
signature=indexed_attestation.signature,
|
||||||
|
domain=get_domain(state, DOMAIN_ATTESTATION, indexed_attestation.data.target.epoch),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `slot_to_epoch`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def slot_to_epoch(slot: Slot) -> Epoch:
|
||||||
|
"""
|
||||||
|
Return the epoch number of ``slot``.
|
||||||
|
"""
|
||||||
|
return Epoch(slot // SLOTS_PER_EPOCH)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `epoch_first_slot`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def epoch_first_slot(epoch: Epoch) -> Slot:
|
||||||
|
"""
|
||||||
|
Return the first slot of ``epoch``.
|
||||||
|
"""
|
||||||
|
return Slot(epoch * SLOTS_PER_EPOCH)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `delayed_activation_exit_epoch`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
|
||||||
|
"""
|
||||||
|
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
|
||||||
|
"""
|
||||||
|
return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `bls_domain`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def bls_domain(domain_type: int, fork_version: bytes=b'\x00' * 4) -> int:
|
||||||
|
"""
|
||||||
|
Return the BLS domain for the ``domain_type`` and ``fork_version``.
|
||||||
|
"""
|
||||||
|
return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
|
||||||
|
```
|
||||||
|
|
||||||
### Beacon state getters
|
### Beacon state getters
|
||||||
|
|
||||||
#### `get_current_epoch`
|
#### `get_current_epoch`
|
||||||
|
@ -706,7 +825,7 @@ def get_block_root(state: BeaconState, epoch: Epoch) -> Hash:
|
||||||
"""
|
"""
|
||||||
Return the block root at a recent ``epoch``.
|
Return the block root at a recent ``epoch``.
|
||||||
"""
|
"""
|
||||||
return get_block_root_at_slot(state, epoch_start_slot(epoch))
|
return get_block_root_at_slot(state, epoch_first_slot(epoch))
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_block_root_at_slot`
|
#### `get_block_root_at_slot`
|
||||||
|
@ -824,10 +943,10 @@ def get_shard_delta(state: BeaconState, epoch: Epoch) -> Shard:
|
||||||
return Shard(min(get_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH))
|
return Shard(min(get_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH))
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_beacon_proposer_index`
|
#### `get_proposer_index`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
|
def get_proposer_index(state: BeaconState) -> ValidatorIndex:
|
||||||
"""
|
"""
|
||||||
Return the beacon proposer index at the current epoch.
|
Return the beacon proposer index at the current epoch.
|
||||||
"""
|
"""
|
||||||
|
@ -857,7 +976,7 @@ def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot
|
||||||
"""
|
"""
|
||||||
committee_count = get_committee_count(state, data.target.epoch)
|
committee_count = get_committee_count(state, data.target.epoch)
|
||||||
offset = (data.crosslink.shard + SHARD_COUNT - get_start_shard(state, data.target.epoch)) % SHARD_COUNT
|
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))
|
return Slot(epoch_first_slot(data.target.epoch) + offset // (committee_count // SLOTS_PER_EPOCH))
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_compact_committees_root`
|
#### `get_compact_committees_root`
|
||||||
|
@ -936,63 +1055,14 @@ def get_attesting_indices(state: BeaconState,
|
||||||
return set(index for i, index in enumerate(committee) if bits[i])
|
return set(index for i, index in enumerate(committee) if bits[i])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### State mutators
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### `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)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `delayed_activation_exit_epoch`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
|
|
||||||
"""
|
|
||||||
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
|
|
||||||
"""
|
|
||||||
return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `increase_balance`
|
#### `increase_balance`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
||||||
"""
|
"""
|
||||||
Increase validator balance by ``delta``.
|
Increase the validator balance at index ``index`` by ``delta``.
|
||||||
"""
|
"""
|
||||||
state.balances[index] += delta
|
state.balances[index] += delta
|
||||||
```
|
```
|
||||||
|
@ -1002,91 +1072,17 @@ def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) ->
|
||||||
```python
|
```python
|
||||||
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
|
||||||
"""
|
"""
|
||||||
Decrease validator balance by ``delta`` with underflow protection.
|
Decrease the validator balance at index ``index`` by ``delta``, with underflow protection.
|
||||||
"""
|
"""
|
||||||
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
|
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `shuffle_index`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def shuffle_index(index: ValidatorIndex, index_count: int, seed: Hash) -> ValidatorIndex:
|
|
||||||
"""
|
|
||||||
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
|
|
||||||
"""
|
|
||||||
assert index < index_count
|
|
||||||
assert index_count <= 2**40
|
|
||||||
|
|
||||||
# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
|
|
||||||
# See the 'generalized domain' algorithm on page 3
|
|
||||||
for current_round in range(SHUFFLE_ROUND_COUNT):
|
|
||||||
pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count
|
|
||||||
flip = ValidatorIndex((pivot + index_count - index) % index_count)
|
|
||||||
position = max(index, flip)
|
|
||||||
source = hash(
|
|
||||||
seed + int_to_bytes(current_round, length=1) +
|
|
||||||
int_to_bytes(position // 256, length=4)
|
|
||||||
)
|
|
||||||
byte = source[(position % 256) // 8]
|
|
||||||
bit = (byte >> (position % 8)) % 2
|
|
||||||
index = flip if bit else index
|
|
||||||
|
|
||||||
return ValidatorIndex(index)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `compute_committee`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def compute_committee(indices: Sequence[ValidatorIndex],
|
|
||||||
seed: Hash, index: int, count: int) -> Sequence[ValidatorIndex]:
|
|
||||||
start = (len(indices) * index) // count
|
|
||||||
end = (len(indices) * (index + 1)) // count
|
|
||||||
return [indices[shuffle_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `validate_indexed_attestation`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def validate_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> None:
|
|
||||||
"""
|
|
||||||
Verify validity of ``indexed_attestation``.
|
|
||||||
"""
|
|
||||||
bit_0_indices = indexed_attestation.custody_bit_0_indices
|
|
||||||
bit_1_indices = indexed_attestation.custody_bit_1_indices
|
|
||||||
|
|
||||||
# Verify no index has custody bit equal to 1 [to be removed in phase 1]
|
|
||||||
assert len(bit_1_indices) == 0
|
|
||||||
# Verify max number of indices
|
|
||||||
assert len(bit_0_indices) + len(bit_1_indices) <= MAX_VALIDATORS_PER_COMMITTEE
|
|
||||||
# Verify index sets are disjoint
|
|
||||||
assert len(set(bit_0_indices).intersection(bit_1_indices)) == 0
|
|
||||||
# Verify indices are sorted
|
|
||||||
assert bit_0_indices == sorted(bit_0_indices) and bit_1_indices == sorted(bit_1_indices)
|
|
||||||
# Verify aggregate signature
|
|
||||||
assert bls_verify_multiple(
|
|
||||||
pubkeys=[
|
|
||||||
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_0_indices]),
|
|
||||||
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_1_indices]),
|
|
||||||
],
|
|
||||||
message_hashes=[
|
|
||||||
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)),
|
|
||||||
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)),
|
|
||||||
],
|
|
||||||
signature=indexed_attestation.signature,
|
|
||||||
domain=get_domain(state, DOMAIN_ATTESTATION, indexed_attestation.data.target.epoch),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Routines for updating validator status
|
|
||||||
|
|
||||||
*Note*: All functions in this section mutate `state`.
|
|
||||||
|
|
||||||
#### `initiate_validator_exit`
|
#### `initiate_validator_exit`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
||||||
"""
|
"""
|
||||||
Initiate the exit of the validator of the given ``index``.
|
Initiate the exit of the validator with index ``index``.
|
||||||
"""
|
"""
|
||||||
# Return if validator already initiated exit
|
# Return if validator already initiated exit
|
||||||
validator = state.validators[index]
|
validator = state.validators[index]
|
||||||
|
@ -1123,7 +1119,7 @@ def slash_validator(state: BeaconState,
|
||||||
decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT)
|
decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT)
|
||||||
|
|
||||||
# Apply proposer and whistleblower rewards
|
# Apply proposer and whistleblower rewards
|
||||||
proposer_index = get_beacon_proposer_index(state)
|
proposer_index = get_proposer_index(state)
|
||||||
if whistleblower_index is None:
|
if whistleblower_index is None:
|
||||||
whistleblower_index = proposer_index
|
whistleblower_index = proposer_index
|
||||||
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
|
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
|
||||||
|
@ -1134,22 +1130,12 @@ def slash_validator(state: BeaconState,
|
||||||
|
|
||||||
## Genesis
|
## Genesis
|
||||||
|
|
||||||
### Genesis state
|
Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 block, let `candidate_state = initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` where:
|
||||||
|
|
||||||
Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 block, call `initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` where:
|
|
||||||
|
|
||||||
* `eth1_block_hash` is the hash of the Ethereum 1.0 block
|
* `eth1_block_hash` is the hash of the Ethereum 1.0 block
|
||||||
* `eth1_timestamp` is the Unix timestamp corresponding to `eth1_block_hash`
|
* `eth1_timestamp` is the Unix timestamp corresponding to `eth1_block_hash`
|
||||||
* `deposits` is the sequence of all deposits, ordered chronologically, up to the block with hash `eth1_block_hash`
|
* `deposits` is the sequence of all deposits, ordered chronologically, up to the block with hash `eth1_block_hash`
|
||||||
|
|
||||||
The genesis state `genesis_state` is the return value of calling `initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` only if `is_valid_genesis_state(genesis_state) is True`.
|
|
||||||
|
|
||||||
Implementations can choose to support different (more optimized) variations of the below initialization approach:
|
|
||||||
- Build the `genesis_state` from a stream of deposits by incrementally updating the `state.eth1_data.deposit_root`.
|
|
||||||
- Compute deposit proofs for the final `state.eth1_data.deposit_root`, and process as a pre-determined collection.
|
|
||||||
|
|
||||||
*Note*: The two constants `MIN_GENESIS_TIME` and `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` have yet to be agreed upon by the community, and can be updated as necessary.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash,
|
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash,
|
||||||
eth1_timestamp: uint64,
|
eth1_timestamp: uint64,
|
||||||
|
@ -1175,22 +1161,27 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash,
|
||||||
validator.activation_epoch = GENESIS_EPOCH
|
validator.activation_epoch = GENESIS_EPOCH
|
||||||
|
|
||||||
# Populate compact_committees_roots
|
# Populate compact_committees_roots
|
||||||
genesis_committee_root = get_compact_committees_root(state, GENESIS_EPOCH)
|
committee_root = get_compact_committees_root(state, GENESIS_EPOCH)
|
||||||
for index in range(EPOCHS_PER_HISTORICAL_VECTOR):
|
for index in range(EPOCHS_PER_HISTORICAL_VECTOR):
|
||||||
state.compact_committees_roots[index] = genesis_committee_root
|
state.compact_committees_roots[index] = committee_root
|
||||||
return state
|
return state
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Genesis state
|
||||||
|
|
||||||
|
Let `genesis_state = candidate_state` whenever `is_valid_genesis_state(candidate_state) is True` for the first time.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def is_valid_genesis_state(state: BeaconState) -> bool:
|
def is_valid_genesis_state(state: BeaconState) -> bool:
|
||||||
if state.genesis_time < MIN_GENESIS_TIME:
|
if state.genesis_time < MIN_GENESIS_TIME:
|
||||||
return False
|
return False
|
||||||
elif len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
|
if len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
|
||||||
return False
|
return False
|
||||||
else:
|
return True
|
||||||
return True
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*Note*: The `is_valid_genesis_state` function (including `MIN_GENESIS_TIME` and `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT`) is a placeholder for testing. It has yet to be finalized by the community, and can be updated as necessary.
|
||||||
|
|
||||||
### Genesis block
|
### Genesis block
|
||||||
|
|
||||||
Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`.
|
Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`.
|
||||||
|
@ -1287,7 +1278,7 @@ def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> Sequence
|
||||||
```python
|
```python
|
||||||
def get_unslashed_attesting_indices(state: BeaconState,
|
def get_unslashed_attesting_indices(state: BeaconState,
|
||||||
attestations: Sequence[PendingAttestation]) -> Set[ValidatorIndex]:
|
attestations: Sequence[PendingAttestation]) -> Set[ValidatorIndex]:
|
||||||
output = set() # type: Set[ValidatorIndex]
|
output = set() # Type: Set[ValidatorIndex]
|
||||||
for a in attestations:
|
for a in attestations:
|
||||||
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
|
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
|
||||||
return set(filter(lambda index: not state.validators[index].slashed, list(output)))
|
return set(filter(lambda index: not state.validators[index].slashed, list(output)))
|
||||||
|
@ -1566,7 +1557,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
||||||
body_root=hash_tree_root(block.body),
|
body_root=hash_tree_root(block.body),
|
||||||
)
|
)
|
||||||
# Verify proposer is not slashed
|
# Verify proposer is not slashed
|
||||||
proposer = state.validators[get_beacon_proposer_index(state)]
|
proposer = state.validators[get_proposer_index(state)]
|
||||||
assert not proposer.slashed
|
assert not proposer.slashed
|
||||||
# Verify proposer signature
|
# Verify proposer signature
|
||||||
assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
||||||
|
@ -1578,7 +1569,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
||||||
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
|
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||||
epoch = get_current_epoch(state)
|
epoch = get_current_epoch(state)
|
||||||
# Verify RANDAO reveal
|
# Verify RANDAO reveal
|
||||||
proposer = state.validators[get_beacon_proposer_index(state)]
|
proposer = state.validators[get_proposer_index(state)]
|
||||||
assert bls_verify(proposer.pubkey, hash_tree_root(epoch), body.randao_reveal, get_domain(state, DOMAIN_RANDAO))
|
assert bls_verify(proposer.pubkey, hash_tree_root(epoch), body.randao_reveal, get_domain(state, DOMAIN_RANDAO))
|
||||||
# Mix in RANDAO reveal
|
# Mix in RANDAO reveal
|
||||||
mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
|
mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
|
||||||
|
@ -1620,9 +1611,6 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
|
def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
|
||||||
"""
|
|
||||||
Process ``ProposerSlashing`` operation.
|
|
||||||
"""
|
|
||||||
proposer = state.validators[proposer_slashing.proposer_index]
|
proposer = state.validators[proposer_slashing.proposer_index]
|
||||||
# Verify that the epoch is the same
|
# Verify that the epoch is the same
|
||||||
assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot)
|
assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot)
|
||||||
|
@ -1642,9 +1630,6 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
|
def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
|
||||||
"""
|
|
||||||
Process ``AttesterSlashing`` operation.
|
|
||||||
"""
|
|
||||||
attestation_1 = attester_slashing.attestation_1
|
attestation_1 = attester_slashing.attestation_1
|
||||||
attestation_2 = attester_slashing.attestation_2
|
attestation_2 = attester_slashing.attestation_2
|
||||||
assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
|
assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
|
||||||
|
@ -1665,9 +1650,6 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||||
"""
|
|
||||||
Process ``Attestation`` operation.
|
|
||||||
"""
|
|
||||||
data = attestation.data
|
data = attestation.data
|
||||||
assert data.crosslink.shard < SHARD_COUNT
|
assert data.crosslink.shard < SHARD_COUNT
|
||||||
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
|
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
|
||||||
|
@ -1679,7 +1661,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||||
data=data,
|
data=data,
|
||||||
aggregation_bits=attestation.aggregation_bits,
|
aggregation_bits=attestation.aggregation_bits,
|
||||||
inclusion_delay=state.slot - attestation_slot,
|
inclusion_delay=state.slot - attestation_slot,
|
||||||
proposer_index=get_beacon_proposer_index(state),
|
proposer_index=get_proposer_index(state),
|
||||||
)
|
)
|
||||||
|
|
||||||
if data.target.epoch == get_current_epoch(state):
|
if data.target.epoch == get_current_epoch(state):
|
||||||
|
@ -1705,9 +1687,6 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||||
"""
|
|
||||||
Process an Eth1 deposit, registering a validator or increasing its balance.
|
|
||||||
"""
|
|
||||||
# Verify the Merkle branch
|
# Verify the Merkle branch
|
||||||
assert is_valid_merkle_branch(
|
assert is_valid_merkle_branch(
|
||||||
leaf=hash_tree_root(deposit.data),
|
leaf=hash_tree_root(deposit.data),
|
||||||
|
@ -1754,9 +1733,6 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
||||||
"""
|
|
||||||
Process ``VoluntaryExit`` operation.
|
|
||||||
"""
|
|
||||||
validator = state.validators[exit.validator_index]
|
validator = state.validators[exit.validator_index]
|
||||||
# Verify the validator is active
|
# Verify the validator is active
|
||||||
assert is_active_validator(validator, get_current_epoch(state))
|
assert is_active_validator(validator, get_current_epoch(state))
|
||||||
|
@ -1777,9 +1753,6 @@ def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_transfer(state: BeaconState, transfer: Transfer) -> None:
|
def process_transfer(state: BeaconState, transfer: Transfer) -> None:
|
||||||
"""
|
|
||||||
Process ``Transfer`` operation.
|
|
||||||
"""
|
|
||||||
# Verify the balance the covers amount and fee (with overflow protection)
|
# Verify the balance the covers amount and fee (with overflow protection)
|
||||||
assert state.balances[transfer.sender] >= max(transfer.amount + transfer.fee, transfer.amount, transfer.fee)
|
assert state.balances[transfer.sender] >= max(transfer.amount + transfer.fee, transfer.amount, transfer.fee)
|
||||||
# A transfer is valid in only one slot
|
# A transfer is valid in only one slot
|
||||||
|
@ -1803,7 +1776,7 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None:
|
||||||
# Process the transfer
|
# Process the transfer
|
||||||
decrease_balance(state, transfer.sender, transfer.amount + transfer.fee)
|
decrease_balance(state, transfer.sender, transfer.amount + transfer.fee)
|
||||||
increase_balance(state, transfer.recipient, transfer.amount)
|
increase_balance(state, transfer.recipient, transfer.amount)
|
||||||
increase_balance(state, get_beacon_proposer_index(state), transfer.fee)
|
increase_balance(state, get_proposer_index(state), transfer.fee)
|
||||||
# Verify balances are not dust
|
# Verify balances are not dust
|
||||||
assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT)
|
assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT)
|
||||||
assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT)
|
assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT)
|
||||||
|
|
|
@ -124,7 +124,7 @@ def get_latest_attesting_balance(store: Store, root: Hash) -> Gwei:
|
||||||
def get_head(store: Store) -> Hash:
|
def get_head(store: Store) -> Hash:
|
||||||
# Execute the LMD-GHOST fork choice
|
# Execute the LMD-GHOST fork choice
|
||||||
head = store.justified_checkpoint.root
|
head = store.justified_checkpoint.root
|
||||||
justified_slot = epoch_start_slot(store.justified_checkpoint.epoch)
|
justified_slot = epoch_first_slot(store.justified_checkpoint.epoch)
|
||||||
while True:
|
while True:
|
||||||
children = [
|
children = [
|
||||||
root for root in store.blocks.keys()
|
root for root in store.blocks.keys()
|
||||||
|
@ -162,7 +162,7 @@ def on_block(store: Store, block: BeaconBlock) -> None:
|
||||||
store.finalized_checkpoint.root
|
store.finalized_checkpoint.root
|
||||||
)
|
)
|
||||||
# Check that block is later than the finalized epoch slot
|
# Check that block is later than the finalized epoch slot
|
||||||
assert block.slot > epoch_start_slot(store.finalized_checkpoint.epoch)
|
assert block.slot > epoch_first_slot(store.finalized_checkpoint.epoch)
|
||||||
# Check the block is valid and compute the post-state
|
# Check the block is valid and compute the post-state
|
||||||
state = state_transition(pre_state, block)
|
state = state_transition(pre_state, block)
|
||||||
# Add new state for this block to the store
|
# 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
|
# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrivesr
|
||||||
base_state = store.block_states[target.root].copy()
|
base_state = store.block_states[target.root].copy()
|
||||||
assert store.time >= base_state.genesis_time + epoch_start_slot(target.epoch) * SECONDS_PER_SLOT
|
assert store.time >= base_state.genesis_time + epoch_first_slot(target.epoch) * SECONDS_PER_SLOT
|
||||||
|
|
||||||
# Store target checkpoint state if not yet seen
|
# Store target checkpoint state if not yet seen
|
||||||
if target not in store.checkpoint_states:
|
if target not in store.checkpoint_states:
|
||||||
process_slots(base_state, epoch_start_slot(target.epoch))
|
process_slots(base_state, epoch_first_slot(target.epoch))
|
||||||
store.checkpoint_states[target] = base_state
|
store.checkpoint_states[target] = base_state
|
||||||
target_state = store.checkpoint_states[target]
|
target_state = store.checkpoint_states[target]
|
||||||
|
|
||||||
|
|
|
@ -382,7 +382,7 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) ->
|
||||||
revealer.next_custody_reveal_period += 1
|
revealer.next_custody_reveal_period += 1
|
||||||
|
|
||||||
# Reward Block Preposer
|
# Reward Block Preposer
|
||||||
proposer_index = get_beacon_proposer_index(state)
|
proposer_index = get_proposer_index(state)
|
||||||
increase_balance(
|
increase_balance(
|
||||||
state,
|
state,
|
||||||
proposer_index,
|
proposer_index,
|
||||||
|
@ -452,7 +452,7 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived
|
||||||
)
|
)
|
||||||
|
|
||||||
# Apply penalty
|
# Apply penalty
|
||||||
proposer_index = get_beacon_proposer_index(state)
|
proposer_index = get_proposer_index(state)
|
||||||
whistleblower_index = reveal.masker_index
|
whistleblower_index = reveal.masker_index
|
||||||
whistleblowing_reward = Gwei(penalty // WHISTLEBLOWER_REWARD_QUOTIENT)
|
whistleblowing_reward = Gwei(penalty // WHISTLEBLOWER_REWARD_QUOTIENT)
|
||||||
proposer_reward = Gwei(whistleblowing_reward // PROPOSER_REWARD_QUOTIENT)
|
proposer_reward = Gwei(whistleblowing_reward // PROPOSER_REWARD_QUOTIENT)
|
||||||
|
@ -493,7 +493,7 @@ def process_chunk_challenge(state: BeaconState, challenge: CustodyChunkChallenge
|
||||||
# Add new chunk challenge record
|
# Add new chunk challenge record
|
||||||
new_record = CustodyChunkChallengeRecord(
|
new_record = CustodyChunkChallengeRecord(
|
||||||
challenge_index=state.custody_challenge_index,
|
challenge_index=state.custody_challenge_index,
|
||||||
challenger_index=get_beacon_proposer_index(state),
|
challenger_index=get_proposer_index(state),
|
||||||
responder_index=challenge.responder_index,
|
responder_index=challenge.responder_index,
|
||||||
inclusion_epoch=get_current_epoch(state),
|
inclusion_epoch=get_current_epoch(state),
|
||||||
data_root=challenge.attestation.data.crosslink.data_root,
|
data_root=challenge.attestation.data.crosslink.data_root,
|
||||||
|
@ -610,7 +610,7 @@ def process_chunk_challenge_response(state: BeaconState,
|
||||||
records = state.custody_chunk_challenge_records
|
records = state.custody_chunk_challenge_records
|
||||||
records[records.index(challenge)] = CustodyChunkChallengeRecord()
|
records[records.index(challenge)] = CustodyChunkChallengeRecord()
|
||||||
# Reward the proposer
|
# Reward the proposer
|
||||||
proposer_index = get_beacon_proposer_index(state)
|
proposer_index = get_proposer_index(state)
|
||||||
increase_balance(state, proposer_index, Gwei(get_base_reward(state, proposer_index) // MINOR_REWARD_QUOTIENT))
|
increase_balance(state, proposer_index, Gwei(get_base_reward(state, proposer_index) // MINOR_REWARD_QUOTIENT))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ def get_committee_assignment(
|
||||||
assert epoch <= next_epoch
|
assert epoch <= next_epoch
|
||||||
|
|
||||||
committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH
|
committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH
|
||||||
start_slot = epoch_start_slot(epoch)
|
start_slot = epoch_first_slot(epoch)
|
||||||
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
|
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
|
||||||
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
|
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
|
||||||
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT
|
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT
|
||||||
|
@ -162,7 +162,7 @@ A validator can use the following function to see if they are supposed to propos
|
||||||
```python
|
```python
|
||||||
def is_proposer(state: BeaconState,
|
def is_proposer(state: BeaconState,
|
||||||
validator_index: ValidatorIndex) -> bool:
|
validator_index: ValidatorIndex) -> bool:
|
||||||
return get_beacon_proposer_index(state) == validator_index
|
return get_proposer_index(state) == validator_index
|
||||||
```
|
```
|
||||||
|
|
||||||
*Note*: To see if a validator is assigned to propose during the slot, the beacon state must be in the epoch in question. At the epoch boundaries, the validator must run an epoch transition into the epoch to successfully check the proposal assignment of the first slot.
|
*Note*: To see if a validator is assigned to propose during the slot, the beacon state must be in the epoch in question. At the epoch boundaries, the validator must run an epoch transition into the epoch to successfully check the proposal assignment of the first slot.
|
||||||
|
@ -307,7 +307,7 @@ 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.
|
* 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:
|
*Note*: `epoch_boundary_block_root` can be looked up in the state using:
|
||||||
* Let `start_slot = epoch_start_slot(get_current_epoch(head_state))`.
|
* Let `start_slot = epoch_first_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)`.
|
* Let `epoch_boundary_block_root = signing_root(head_block) if start_slot == head_state.slot else get_block_root(state, start_slot)`.
|
||||||
|
|
||||||
##### Crosslink vote
|
##### Crosslink vote
|
||||||
|
|
|
@ -15,15 +15,15 @@ def build_attestation_data(spec, state, slot, shard):
|
||||||
else:
|
else:
|
||||||
block_root = spec.get_block_root_at_slot(state, slot)
|
block_root = spec.get_block_root_at_slot(state, slot)
|
||||||
|
|
||||||
current_epoch_start_slot = spec.epoch_start_slot(spec.get_current_epoch(state))
|
current_epoch_first_slot = spec.epoch_first_slot(spec.get_current_epoch(state))
|
||||||
if slot < current_epoch_start_slot:
|
if slot < current_epoch_first_slot:
|
||||||
epoch_boundary_root = spec.get_block_root(state, spec.get_previous_epoch(state))
|
epoch_boundary_root = spec.get_block_root(state, spec.get_previous_epoch(state))
|
||||||
elif slot == current_epoch_start_slot:
|
elif slot == current_epoch_first_slot:
|
||||||
epoch_boundary_root = block_root
|
epoch_boundary_root = block_root
|
||||||
else:
|
else:
|
||||||
epoch_boundary_root = spec.get_block_root(state, spec.get_current_epoch(state))
|
epoch_boundary_root = spec.get_block_root(state, spec.get_current_epoch(state))
|
||||||
|
|
||||||
if slot < current_epoch_start_slot:
|
if slot < current_epoch_first_slot:
|
||||||
source_epoch = state.previous_justified_checkpoint.epoch
|
source_epoch = state.previous_justified_checkpoint.epoch
|
||||||
source_root = state.previous_justified_checkpoint.root
|
source_root = state.previous_justified_checkpoint.root
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -12,7 +12,7 @@ def sign_block(spec, state, block, proposer_index=None):
|
||||||
|
|
||||||
if proposer_index is None:
|
if proposer_index is None:
|
||||||
if block.slot == state.slot:
|
if block.slot == state.slot:
|
||||||
proposer_index = spec.get_beacon_proposer_index(state)
|
proposer_index = spec.get_proposer_index(state)
|
||||||
else:
|
else:
|
||||||
if spec.slot_to_epoch(state.slot) + 1 > spec.slot_to_epoch(block.slot):
|
if spec.slot_to_epoch(state.slot) + 1 > spec.slot_to_epoch(block.slot):
|
||||||
print("warning: block slot far away, and no proposer index manually given."
|
print("warning: block slot far away, and no proposer index manually given."
|
||||||
|
@ -20,7 +20,7 @@ def sign_block(spec, state, block, proposer_index=None):
|
||||||
# use stub state to get proposer index of future slot
|
# use stub state to get proposer index of future slot
|
||||||
stub_state = deepcopy(state)
|
stub_state = deepcopy(state)
|
||||||
spec.process_slots(stub_state, block.slot)
|
spec.process_slots(stub_state, block.slot)
|
||||||
proposer_index = spec.get_beacon_proposer_index(stub_state)
|
proposer_index = spec.get_proposer_index(stub_state)
|
||||||
|
|
||||||
privkey = privkeys[proposer_index]
|
privkey = privkeys[proposer_index]
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
|
||||||
+ attester_slashing.attestation_1.custody_bit_1_indices
|
+ attester_slashing.attestation_1.custody_bit_1_indices
|
||||||
)
|
)
|
||||||
|
|
||||||
proposer_index = spec.get_beacon_proposer_index(state)
|
proposer_index = spec.get_proposer_index(state)
|
||||||
pre_proposer_balance = get_balance(state, proposer_index)
|
pre_proposer_balance = get_balance(state, proposer_index)
|
||||||
pre_slashings = {slashed_index: get_balance(state, slashed_index) for slashed_index in slashed_indices}
|
pre_slashings = {slashed_index: get_balance(state, slashed_index) for slashed_index in slashed_indices}
|
||||||
pre_withdrawalable_epochs = {
|
pre_withdrawalable_epochs = {
|
||||||
|
|
|
@ -75,7 +75,7 @@ def test_proposer_slashed(spec, state):
|
||||||
# use stub state to get proposer index of next slot
|
# use stub state to get proposer index of next slot
|
||||||
stub_state = deepcopy(state)
|
stub_state = deepcopy(state)
|
||||||
next_slot(spec, stub_state)
|
next_slot(spec, stub_state)
|
||||||
proposer_index = spec.get_beacon_proposer_index(stub_state)
|
proposer_index = spec.get_proposer_index(stub_state)
|
||||||
|
|
||||||
# set proposer to slashed
|
# set proposer to slashed
|
||||||
state.validators[proposer_index].slashed = True
|
state.validators[proposer_index].slashed = True
|
||||||
|
|
|
@ -21,7 +21,7 @@ def run_transfer_processing(spec, state, transfer, valid=True):
|
||||||
yield 'post', None
|
yield 'post', None
|
||||||
return
|
return
|
||||||
|
|
||||||
proposer_index = spec.get_beacon_proposer_index(state)
|
proposer_index = spec.get_proposer_index(state)
|
||||||
pre_transfer_sender_balance = state.balances[transfer.sender]
|
pre_transfer_sender_balance = state.balances[transfer.sender]
|
||||||
pre_transfer_recipient_balance = state.balances[transfer.recipient]
|
pre_transfer_recipient_balance = state.balances[transfer.recipient]
|
||||||
pre_transfer_proposer_balance = state.balances[proposer_index]
|
pre_transfer_proposer_balance = state.balances[proposer_index]
|
||||||
|
|
|
@ -33,7 +33,7 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
|
||||||
total_balance = spec.get_total_active_balance(state)
|
total_balance = spec.get_total_active_balance(state)
|
||||||
remaining_balance = total_balance * 2 // 3
|
remaining_balance = total_balance * 2 // 3
|
||||||
|
|
||||||
start_slot = spec.epoch_start_slot(epoch)
|
start_slot = spec.epoch_first_slot(epoch)
|
||||||
for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH):
|
for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH):
|
||||||
for shard in get_shards_for_slot(spec, state, slot):
|
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).
|
# Check if we already have had sufficient balance. (and undone if we don't want it).
|
||||||
|
@ -80,7 +80,7 @@ def get_checkpoints(spec, epoch):
|
||||||
|
|
||||||
def put_checkpoints_in_block_roots(spec, state, checkpoints):
|
def put_checkpoints_in_block_roots(spec, state, checkpoints):
|
||||||
for c in checkpoints:
|
for c in checkpoints:
|
||||||
state.block_roots[spec.epoch_start_slot(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root
|
state.block_roots[spec.epoch_first_slot(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root
|
||||||
|
|
||||||
|
|
||||||
def finalize_on_234(spec, state, epoch, sufficient_support):
|
def finalize_on_234(spec, state, epoch, sufficient_support):
|
||||||
|
|
|
@ -214,7 +214,7 @@ def test_attester_slashing(spec, state):
|
||||||
# lost whistleblower reward
|
# lost whistleblower reward
|
||||||
assert get_balance(state, validator_index) < get_balance(pre_state, validator_index)
|
assert get_balance(state, validator_index) < get_balance(pre_state, validator_index)
|
||||||
|
|
||||||
proposer_index = spec.get_beacon_proposer_index(state)
|
proposer_index = spec.get_proposer_index(state)
|
||||||
# gained whistleblower reward
|
# gained whistleblower reward
|
||||||
assert (
|
assert (
|
||||||
get_balance(state, proposer_index) >
|
get_balance(state, proposer_index) >
|
||||||
|
|
|
@ -43,7 +43,7 @@ def next_epoch_with_attestations(spec,
|
||||||
block = build_empty_block_for_next_slot(spec, post_state)
|
block = build_empty_block_for_next_slot(spec, post_state)
|
||||||
if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY:
|
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
|
slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
|
||||||
if slot_to_attest >= spec.epoch_start_slot(spec.get_current_epoch(post_state)):
|
if slot_to_attest >= spec.epoch_first_slot(spec.get_current_epoch(post_state)):
|
||||||
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest)
|
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest)
|
||||||
block.body.attestations.append(cur_attestation)
|
block.body.attestations.append(cur_attestation)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue