eth2.0-specs/specs/core/0_beacon-chain.md

1673 lines
63 KiB
Markdown
Raw Normal View History

# Ethereum 2.0 Phase 0 -- The Beacon Chain
2018-09-20 05:20:49 +00:00
2019-05-06 15:30:32 +00:00
**Notice**: This document is a work-in-progress for researchers and implementers.
2018-09-20 05:20:49 +00:00
2018-11-28 07:23:37 +00:00
## Table of contents
2018-12-01 05:29:19 +00:00
<!-- TOC -->
- [Ethereum 2.0 Phase 0 -- The Beacon Chain](#ethereum-20-phase-0----the-beacon-chain)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Notation](#notation)
- [Custom types](#custom-types)
2018-12-01 05:29:19 +00:00
- [Constants](#constants)
2019-06-17 21:19:44 +00:00
- [Configuration](#configuration)
- [Misc](#misc)
2019-02-06 16:34:19 +00:00
- [Gwei values](#gwei-values)
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
2019-01-28 00:25:29 +00:00
- [State list lengths](#state-list-lengths)
2019-05-29 20:40:46 +00:00
- [Rewards and penalties](#rewards-and-penalties)
- [Max operations per block](#max-operations-per-block)
2019-09-22 19:27:42 +00:00
- [Domain types](#domain-types)
2019-06-09 19:41:21 +00:00
- [Containers](#containers)
2019-03-07 18:02:13 +00:00
- [Misc dependencies](#misc-dependencies)
- [`Fork`](#fork)
- [`Checkpoint`](#checkpoint)
- [`Validator`](#validator)
2019-03-07 18:02:13 +00:00
- [`AttestationData`](#attestationdata)
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
2019-03-26 19:40:19 +00:00
- [`IndexedAttestation`](#indexedattestation)
2019-03-07 18:02:13 +00:00
- [`PendingAttestation`](#pendingattestation)
- [`Eth1Data`](#eth1data)
2019-03-08 17:13:05 +00:00
- [`HistoricalBatch`](#historicalbatch)
- [`DepositData`](#depositdata)
2019-06-05 15:50:15 +00:00
- [`BeaconBlockHeader`](#beaconblockheader)
- [Beacon operations](#beacon-operations)
2019-03-07 18:02:13 +00:00
- [`ProposerSlashing`](#proposerslashing)
- [`AttesterSlashing`](#attesterslashing)
- [`Attestation`](#attestation)
- [`Deposit`](#deposit)
- [`VoluntaryExit`](#voluntaryexit)
- [`Transfer`](#transfer)
- [Beacon blocks](#beacon-blocks)
- [`BeaconBlockBody`](#beaconblockbody)
- [`BeaconBlock`](#beaconblock)
- [Beacon state](#beacon-state)
- [`BeaconState`](#beaconstate)
- [Helper functions](#helper-functions)
2019-06-30 09:11:23 +00:00
- [Math](#math)
2019-06-30 09:02:18 +00:00
- [`integer_squareroot`](#integer_squareroot)
- [`xor`](#xor)
2019-07-10 17:11:34 +00:00
- [`int_to_bytes`](#int_to_bytes)
2019-06-30 09:56:14 +00:00
- [`bytes_to_int`](#bytes_to_int)
2019-06-30 09:11:23 +00:00
- [Crypto](#crypto)
2019-06-30 09:02:18 +00:00
- [`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)
2019-06-30 09:11:23 +00:00
- [Predicates](#predicates)
- [`is_active_validator`](#is_active_validator)
- [`is_slashable_validator`](#is_slashable_validator)
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
- [`is_valid_indexed_attestation`](#is_valid_indexed_attestation)
2019-06-30 09:56:14 +00:00
- [`is_valid_merkle_branch`](#is_valid_merkle_branch)
2019-06-30 20:11:17 +00:00
- [Misc](#misc-1)
2019-06-30 19:49:29 +00:00
- [`compute_shuffled_index`](#compute_shuffled_index)
- [`compute_proposer_index`](#compute_proposer_index)
2019-06-30 09:56:14 +00:00
- [`compute_committee`](#compute_committee)
- [`compute_epoch_of_slot`](#compute_epoch_of_slot)
- [`compute_start_slot_of_epoch`](#compute_start_slot_of_epoch)
- [`compute_activation_exit_epoch`](#compute_activation_exit_epoch)
- [`compute_domain`](#compute_domain)
- [Beacon state accessors](#beacon-state-accessors)
2019-06-30 09:02:18 +00:00
- [`get_current_epoch`](#get_current_epoch)
- [`get_previous_epoch`](#get_previous_epoch)
2019-06-30 09:56:14 +00:00
- [`get_block_root`](#get_block_root)
- [`get_block_root_at_slot`](#get_block_root_at_slot)
- [`get_randao_mix`](#get_randao_mix)
- [`get_active_validator_indices`](#get_active_validator_indices)
2019-06-30 13:11:46 +00:00
- [`get_validator_churn_limit`](#get_validator_churn_limit)
2019-06-30 09:56:14 +00:00
- [`get_seed`](#get_seed)
- [`get_crosslink_committee`](#get_crosslink_committee)
2019-06-30 17:42:24 +00:00
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
2019-06-30 09:02:18 +00:00
- [`get_total_balance`](#get_total_balance)
2019-06-30 20:11:17 +00:00
- [`get_total_active_balance`](#get_total_active_balance)
2019-06-30 09:02:18 +00:00
- [`get_domain`](#get_domain)
- [`get_indexed_attestation`](#get_indexed_attestation)
2019-06-30 09:56:14 +00:00
- [`get_attesting_indices`](#get_attesting_indices)
2019-06-30 10:01:54 +00:00
- [Beacon state mutators](#beacon-state-mutators)
2019-06-30 09:56:14 +00:00
- [`increase_balance`](#increase_balance)
- [`decrease_balance`](#decrease_balance)
- [`initiate_validator_exit`](#initiate_validator_exit)
2019-02-12 12:24:19 +00:00
- [`slash_validator`](#slash_validator)
2019-05-05 16:15:05 +00:00
- [Genesis](#genesis)
- [Genesis state](#genesis-state)
- [Genesis block](#genesis-block)
2018-12-01 05:29:19 +00:00
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
2019-05-01 12:29:03 +00:00
- [Epoch processing](#epoch-processing)
2019-03-02 06:40:43 +00:00
- [Helper functions](#helper-functions-1)
- [Justification and finalization](#justification-and-finalization)
2019-05-29 20:40:46 +00:00
- [Rewards and penalties](#rewards-and-penalties-1)
- [Registry updates](#registry-updates)
2019-04-06 10:07:03 +00:00
- [Slashings](#slashings)
2019-01-29 13:17:05 +00:00
- [Final updates](#final-updates)
2019-05-01 12:29:03 +00:00
- [Block processing](#block-processing)
2019-03-07 19:05:34 +00:00
- [Block header](#block-header)
- [RANDAO](#randao)
2019-04-18 08:53:02 +00:00
- [Eth1 data](#eth1-data)
- [Operations](#operations)
2019-03-08 17:34:51 +00:00
- [Proposer slashings](#proposer-slashings)
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Voluntary exits](#voluntary-exits)
- [Transfers](#transfers)
2018-12-01 05:29:19 +00:00
<!-- /TOC -->
2018-11-28 07:23:37 +00:00
## Introduction
2018-09-20 05:20:49 +00:00
This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain.
2019-06-30 13:45:36 +00:00
At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of validators. In the initial deployment phases of Ethereum 2.0, the only mechanism to become a validator is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a validator happens when Ethereum 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior.
The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block and proof-of-stake votes for a beacon block. A sufficient number of attestations for the same shard block create a "crosslink", confirming the shard segment up to that shard block into the beacon chain. Crosslinks also serve as infrastructure for asynchronous cross-shard communication.
2018-09-20 05:20:49 +00:00
2018-11-29 01:56:25 +00:00
## Notation
2019-06-30 13:45:36 +00:00
Code snippets appearing in `this style` are to be interpreted as Python 3 code.
2018-09-20 05:20:49 +00:00
## Custom types
We define the following Python custom types for type hinting and readability:
| Name | SSZ equivalent | Description |
| - | - | - |
| `Slot` | `uint64` | a slot number |
| `Epoch` | `uint64` | an epoch number |
| `Shard` | `uint64` | a shard number |
| `ValidatorIndex` | `uint64` | a validator registry index |
| `Gwei` | `uint64` | an amount in Gwei |
2019-06-30 15:10:22 +00:00
| `Hash` | `Bytes32` | a hash |
2019-06-15 21:32:52 +00:00
| `Version` | `Bytes4` | a fork version number |
2019-09-22 19:27:42 +00:00
| `DomainType` | `Bytes4` | a domain type |
2019-06-30 20:12:02 +00:00
| `Domain` | `Bytes8` | a signature domain |
| `BLSPubkey` | `Bytes48` | a BLS12-381 public key |
| `BLSSignature` | `Bytes96` | a BLS12-381 signature |
2018-11-28 07:23:37 +00:00
## Constants
2018-09-20 05:20:49 +00:00
2019-06-17 21:19:44 +00:00
The following values are (non-configurable) constants used throughout the specification.
| Name | Value |
| - | - |
2019-06-18 14:24:23 +00:00
| `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` |
| `BASE_REWARDS_PER_EPOCH` | `5` |
2019-06-17 21:19:44 +00:00
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
| `SECONDS_PER_DAY` | `86400` |
2019-06-30 19:51:10 +00:00
| `JUSTIFICATION_BITS_LENGTH` | `4` |
2019-06-30 22:21:19 +00:00
| `ENDIANNESS` | `'little'` |
2019-06-17 21:19:44 +00:00
## Configuration
2019-08-19 11:47:09 +00:00
*Note*: The default mainnet configuration values are included here for spec-design purposes. The different configurations for mainnet, testnets, and YAML-based testing can be found in the [`configs/constant_presets`](../../configs) directory. These configurations are updated for releases and may be out of sync during `dev` changes.
2019-04-03 02:35:40 +00:00
### Misc
2019-02-12 13:37:30 +00:00
| Name | Value |
| - | - |
2019-02-12 13:37:30 +00:00
| `SHARD_COUNT` | `2**10` (= 1,024) |
2019-10-13 04:53:43 +00:00
| `MAX_COMMITTEES_PER_SLOT` | `2**5` (= 32) |
2019-02-12 13:37:30 +00:00
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
2019-06-26 12:20:04 +00:00
| `MAX_VALIDATORS_PER_COMMITTEE` | `2**12` (= 4,096) |
2019-04-14 03:14:05 +00:00
| `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) |
2019-04-14 07:28:45 +00:00
| `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) |
2019-05-06 15:30:32 +00:00
| `SHUFFLE_ROUND_COUNT` | `90` |
2019-06-29 20:53:04 +00:00
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) |
| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) |
2019-06-30 19:25:58 +00:00
- 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.)
2019-02-06 16:34:19 +00:00
### Gwei values
| Name | Value |
2019-06-21 20:30:22 +00:00
| - | - |
| `MIN_DEPOSIT_AMOUNT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) |
| `MAX_EFFECTIVE_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) |
| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) |
| `EFFECTIVE_BALANCE_INCREMENT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) |
### Initial values
| Name | Value |
| - | - |
| `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` |
2019-06-30 21:58:02 +00:00
| `BLS_WITHDRAWAL_PREFIX` | `Bytes1(b'\x00')` |
### Time parameters
2019-07-01 03:13:41 +00:00
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
| `SECONDS_PER_SLOT` | `6` | seconds | 6 seconds |
2019-07-01 03:13:41 +00:00
| `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 6 seconds |
| `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
| `MAX_SEED_LOOKAHEAD` | `2**2` (= 4) | epochs | 25.6 minutes |
2019-07-01 03:13:41 +00:00
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes |
2019-03-19 16:21:17 +00:00
2019-01-28 00:25:29 +00:00
### State list lengths
2019-07-01 01:17:03 +00:00
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
2019-07-01 01:17:03 +00:00
| `EPOCHS_PER_HISTORICAL_VECTOR` | `2**16` (= 65,536) | epochs | ~0.8 years |
| `EPOCHS_PER_SLASHINGS_VECTOR` | `2**13` (= 8,192) | epochs | ~36 days |
| `HISTORICAL_ROOTS_LIMIT` | `2**24` (= 16,777,216) | historical roots | ~26,131 years |
| `VALIDATOR_REGISTRY_LIMIT` | `2**40` (= 1,099,511,627,776) | validator spots |
2019-05-29 20:40:46 +00:00
### Rewards and penalties
2018-10-03 07:27:39 +00:00
| Name | Value |
| - | - |
Tweak inclusion delay rewards and set BASE_REWARD_FACTOR Substantive changes: 1) Split the inclusion delay reward between attester and proposer to add up to at most one base reward. This is analogous to the reward logic in `slash_validator`, and makes the `BASE_REWARDS_PER_EPOCH` constant include proposer rewards. 2) Double `BASE_REWARD_FACTOR` to 2^6 (addressing item 4 in #1054). When the total effective balance is 2^17 ETH then maximum annual issuance is a bit below 2^21 ETH. Maximum annual issuance happens when a) all validators make perfect attestations (matching source, target, head, as well as consistent crosslink data), b) all attestations are included as fast as possible (in particular, no skip blocks), and c) there are no slashings. ```python BASE_REWARD_FACTOR = 2**6 SLOTS_PER_EPOCH = 2**6 SECONDS_PER_SLOT = 6 BASE_REWARDS_PER_EPOCH = 5 GWEI_PER_ETH = 10**9 MAX_TOTAL_EFFECTIVE_BALANCE = 2**27 * GWEI_PER_ETH TARGET_MAX_ISSUANCE = 2**21 * GWEI_PER_ETH 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 MAX_REWARDS_PER_EPOCH = MAX_TOTAL_EFFECTIVE_BALANCE * BASE_REWARD_FACTOR // integer_squareroot(MAX_TOTAL_EFFECTIVE_BALANCE) // BASE_REWARDS_PER_EPOCH EPOCHS_PER_YEAR = 365.25*24*60*60 / (SECONDS_PER_SLOT * SLOTS_PER_EPOCH) MAX_REWARDS_PER_YEAR = EPOCHS_PER_YEAR * MAX_REWARDS_PER_EPOCH * BASE_REWARDS_PER_EPOCH print(MAX_REWARDS_PER_YEAR / TARGET_MAX_ISSUANCE) ```
2019-06-10 14:14:32 +00:00
| `BASE_REWARD_FACTOR` | `2**6` (= 64) |
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `2**9` (= 512) |
2019-03-26 13:21:49 +00:00
| `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) |
| `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) |
2019-04-22 06:34:50 +00:00
| `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) |
2018-10-03 07:27:39 +00:00
2019-06-30 19:25:58 +00:00
- The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (about 18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating validators to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline validators after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)`; so after `INVERSE_SQRT_E_DROP_TIME` epochs, it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
### Max operations per block
2018-10-04 13:16:31 +00:00
2018-12-07 01:02:23 +00:00
| Name | Value |
2018-12-07 01:07:26 +00:00
| - | - |
2018-12-07 01:02:23 +00:00
| `MAX_PROPOSER_SLASHINGS` | `2**4` (= 16) |
| `MAX_ATTESTER_SLASHINGS` | `2**0` (= 1) |
2018-12-07 01:02:23 +00:00
| `MAX_ATTESTATIONS` | `2**7` (= 128) |
| `MAX_DEPOSITS` | `2**4` (= 16) |
2019-02-12 12:24:19 +00:00
| `MAX_VOLUNTARY_EXITS` | `2**4` (= 16) |
| `MAX_TRANSFERS` | `0` |
2018-10-04 13:16:31 +00:00
2019-09-22 19:27:42 +00:00
### Domain types
2019-06-30 20:12:02 +00:00
The following types are defined, mapping into `DomainType` (little endian):
2018-11-20 01:13:58 +00:00
2018-12-10 19:55:11 +00:00
| Name | Value |
| - | - |
2019-03-31 16:48:44 +00:00
| `DOMAIN_BEACON_PROPOSER` | `0` |
2019-09-22 19:27:42 +00:00
| `DOMAIN_BEACON_ATTESTER` | `1` |
| `DOMAIN_RANDAO` | `2` |
2019-03-03 11:04:28 +00:00
| `DOMAIN_DEPOSIT` | `3` |
| `DOMAIN_VOLUNTARY_EXIT` | `4` |
| `DOMAIN_TRANSFER` | `5` |
2019-06-09 19:41:21 +00:00
## Containers
The following types are [SimpleSerialize (SSZ)](../simple-serialize.md) containers.
*Note*: The definitions are ordered topologically to facilitate execution of the spec.
*Note*: Fields missing in container instantiations default to their zero value.
2019-03-07 18:02:13 +00:00
### Misc dependencies
2019-03-07 18:02:13 +00:00
#### `Fork`
```python
class Fork(Container):
2019-06-15 21:32:52 +00:00
previous_version: Version
current_version: Version
epoch: Epoch # Epoch of latest fork
```
#### `Checkpoint`
```python
class Checkpoint(Container):
epoch: Epoch
root: Hash
```
#### `Validator`
2018-12-06 23:51:01 +00:00
```python
class Validator(Container):
2019-06-15 21:23:44 +00:00
pubkey: BLSPubkey
withdrawal_credentials: Hash # Commitment to pubkey for withdrawals and transfers
effective_balance: Gwei # Balance at stake
slashed: boolean
2019-06-09 19:41:21 +00:00
# Status epochs
activation_eligibility_epoch: Epoch # When criteria for activation were met
activation_epoch: Epoch
exit_epoch: Epoch
2019-06-15 16:05:01 +00:00
withdrawable_epoch: Epoch # When validator can withdraw or transfer funds
2018-12-06 23:51:01 +00:00
```
2019-03-07 18:02:13 +00:00
#### `AttestationData`
```python
class AttestationData(Container):
slot: Slot
2019-03-12 10:17:34 +00:00
# LMD GHOST vote
2019-06-17 21:21:45 +00:00
beacon_block_root: Hash
2019-03-12 10:17:34 +00:00
# FFG vote
2019-06-22 20:49:53 +00:00
source: Checkpoint
target: Checkpoint
2019-10-12 04:32:46 +00:00
# Committee Index
index: uint64
```
2019-03-07 18:02:13 +00:00
#### `AttestationDataAndCustodyBit`
```python
class AttestationDataAndCustodyBit(Container):
data: AttestationData
custody_bit: bit # Challengeable bit (SSZ-bool, 1 byte) for the custody of crosslink data
```
2019-03-26 19:40:19 +00:00
#### `IndexedAttestation`
2018-12-07 01:02:23 +00:00
2019-03-07 18:02:13 +00:00
```python
class IndexedAttestation(Container):
2019-06-26 12:20:04 +00:00
custody_bit_0_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] # Indices with custody bit equal to 0
custody_bit_1_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] # Indices with custody bit equal to 1
data: AttestationData
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2019-03-07 18:02:13 +00:00
```
#### `PendingAttestation`
```python
class PendingAttestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData
2019-06-09 19:41:21 +00:00
inclusion_delay: Slot
proposer_index: ValidatorIndex
2019-03-07 18:02:13 +00:00
```
#### `Eth1Data`
```python
class Eth1Data(Container):
2019-06-17 21:21:45 +00:00
deposit_root: Hash
deposit_count: uint64
2019-06-17 21:21:45 +00:00
block_hash: Hash
```
2019-03-08 17:13:05 +00:00
#### `HistoricalBatch`
```python
class HistoricalBatch(Container):
2019-06-17 21:21:45 +00:00
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
2019-03-08 17:13:05 +00:00
```
2019-03-15 11:18:06 +00:00
#### `DepositData`
```python
class DepositData(Container):
2019-06-15 21:23:44 +00:00
pubkey: BLSPubkey
2019-06-17 21:21:45 +00:00
withdrawal_credentials: Hash
amount: Gwei
2019-06-15 21:23:44 +00:00
signature: BLSSignature
```
2019-03-07 18:02:13 +00:00
#### `BeaconBlockHeader`
```python
class BeaconBlockHeader(Container):
slot: Slot
2019-06-17 21:21:45 +00:00
parent_root: Hash
state_root: Hash
body_root: Hash
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2019-03-07 18:02:13 +00:00
```
2019-05-14 05:15:03 +00:00
### Beacon operations
2019-03-07 18:02:13 +00:00
#### `ProposerSlashing`
```python
class ProposerSlashing(Container):
proposer_index: ValidatorIndex
header_1: BeaconBlockHeader
header_2: BeaconBlockHeader
2019-03-07 18:02:13 +00:00
```
#### `AttesterSlashing`
```python
class AttesterSlashing(Container):
attestation_1: IndexedAttestation
attestation_2: IndexedAttestation
2019-03-07 18:02:13 +00:00
```
#### `Attestation`
```python
class Attestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData
custody_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
2019-06-15 21:23:44 +00:00
signature: BLSSignature
```
2019-03-07 18:02:13 +00:00
#### `Deposit`
2019-03-07 18:02:13 +00:00
```python
class Deposit(Container):
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit data list root
data: DepositData
2019-03-07 18:02:13 +00:00
```
#### `VoluntaryExit`
2018-12-07 01:02:23 +00:00
```python
class VoluntaryExit(Container):
epoch: Epoch # Earliest epoch when voluntary exit can be processed
validator_index: ValidatorIndex
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2018-12-07 01:02:23 +00:00
```
2019-03-07 18:02:13 +00:00
#### `Transfer`
```python
class Transfer(Container):
sender: ValidatorIndex
recipient: ValidatorIndex
amount: Gwei
fee: Gwei
slot: Slot # Slot at which transfer must be processed
pubkey: BLSPubkey # Withdrawal pubkey
signature: BLSSignature # Signature checked against withdrawal pubkey
```
2019-03-07 18:02:13 +00:00
### Beacon blocks
2018-12-07 01:02:23 +00:00
2019-03-07 18:02:13 +00:00
#### `BeaconBlockBody`
```python
class BeaconBlockBody(Container):
2019-06-15 21:23:44 +00:00
randao_reveal: BLSSignature
eth1_data: Eth1Data # Eth1 data vote
graffiti: Bytes32 # Arbitrary data
2019-06-09 19:41:21 +00:00
# Operations
2019-06-20 18:03:11 +00:00
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]
attestations: List[Attestation, MAX_ATTESTATIONS]
deposits: List[Deposit, MAX_DEPOSITS]
voluntary_exits: List[VoluntaryExit, MAX_VOLUNTARY_EXITS]
transfers: List[Transfer, MAX_TRANSFERS]
2019-03-03 11:04:28 +00:00
```
2019-03-07 18:02:13 +00:00
#### `BeaconBlock`
2019-03-03 11:04:28 +00:00
```python
class BeaconBlock(Container):
slot: Slot
2019-06-17 21:21:45 +00:00
parent_root: Hash
state_root: Hash
body: BeaconBlockBody
2019-06-15 21:23:44 +00:00
signature: BLSSignature
```
2019-03-07 18:02:13 +00:00
### Beacon state
2018-09-20 05:20:49 +00:00
#### `BeaconState`
2018-09-20 05:20:49 +00:00
```python
class BeaconState(Container):
2019-06-09 19:41:21 +00:00
# Versioning
genesis_time: uint64
2019-06-09 19:41:21 +00:00
slot: Slot
fork: Fork
# History
2019-06-15 14:09:50 +00:00
latest_block_header: BeaconBlockHeader
2019-06-09 19:41:21 +00:00
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
2019-06-24 21:38:36 +00:00
historical_roots: List[Hash, HISTORICAL_ROOTS_LIMIT]
2019-06-09 19:41:21 +00:00
# Eth1
eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data, SLOTS_PER_ETH1_VOTING_PERIOD]
2019-06-09 19:41:21 +00:00
eth1_deposit_index: uint64
# Registry
2019-06-24 21:38:36 +00:00
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
2019-06-09 19:41:21 +00:00
# Shuffling
2019-10-13 04:53:43 +00:00
start_index: uint64
randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR]
2019-06-09 19:41:21 +00:00
# Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
2019-06-09 19:41:21 +00:00
# Attestations
previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
2019-06-09 19:41:21 +00:00
# Finality
2019-06-28 11:23:22 +00:00
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
previous_justified_checkpoint: Checkpoint # Previous epoch snapshot
current_justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
2018-09-20 05:20:49 +00:00
```
## Helper functions
2019-05-06 15:30:32 +00:00
*Note*: The definitions below are for specification purposes and are not necessarily optimal implementations.
2019-06-30 09:02:18 +00:00
### Math
#### `integer_squareroot`
```python
2019-06-30 19:51:10 +00:00
def integer_squareroot(n: uint64) -> uint64:
2019-06-30 09:02:18 +00:00
"""
Return the largest integer ``x`` such that ``x**2 <= n``.
"""
x = n
y = (x + 1) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
```
#### `xor`
2019-03-04 22:49:21 +00:00
```python
2019-07-05 14:03:37 +00:00
def xor(bytes_1: Bytes32, bytes_2: Bytes32) -> Bytes32:
2019-06-30 09:02:18 +00:00
"""
2019-06-30 17:42:24 +00:00
Return the exclusive-or of two 32-byte strings.
2019-06-30 09:02:18 +00:00
"""
2019-07-05 14:03:37 +00:00
return Bytes32(a ^ b for a, b in zip(bytes_1, bytes_2))
2019-03-04 22:49:21 +00:00
```
2019-07-10 17:11:34 +00:00
#### `int_to_bytes`
2019-06-30 09:56:14 +00:00
```python
2019-06-30 19:51:10 +00:00
def int_to_bytes(n: uint64, length: uint64) -> bytes:
2019-06-30 09:56:14 +00:00
"""
2019-06-30 19:51:10 +00:00
Return the ``length``-byte serialization of ``n``.
2019-06-30 09:56:14 +00:00
"""
2019-06-30 19:51:10 +00:00
return n.to_bytes(length, ENDIANNESS)
2019-06-30 09:56:14 +00:00
```
#### `bytes_to_int`
```python
2019-06-30 19:51:10 +00:00
def bytes_to_int(data: bytes) -> uint64:
2019-06-30 09:56:14 +00:00
"""
Return the integer deserialization of ``data``.
"""
return int.from_bytes(data, ENDIANNESS)
```
2019-06-30 09:02:18 +00:00
### Crypto
#### `hash`
2019-06-30 09:56:14 +00:00
`def hash(data: bytes) -> Hash` is SHA256.
2019-06-30 09:02:18 +00:00
#### `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).
2019-06-30 09:02:18 +00:00
#### `signing_root`
2019-06-30 09:02:18 +00:00
`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).
2019-06-30 09:02:18 +00:00
#### `bls_verify`
2019-02-15 00:23:03 +00:00
2019-06-30 09:02:18 +00:00
`bls_verify` is a function for verifying a BLS signature, as defined in the [BLS Signature spec](../bls_signature.md#bls_verify).
2019-02-15 00:23:03 +00:00
2019-06-30 09:02:18 +00:00
#### `bls_verify_multiple`
2019-06-30 09:02:18 +00:00
`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`
2019-06-30 09:02:18 +00:00
`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).
2019-06-30 09:11:23 +00:00
### Predicates
#### `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)
```
#### `is_slashable_attestation_data`
```python
def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
"""
Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules.
"""
return (
# Double vote
(data_1 != data_2 and data_1.target.epoch == data_2.target.epoch) or
# Surround vote
(data_1.source.epoch < data_2.source.epoch and data_2.target.epoch < data_1.target.epoch)
)
```
#### `is_valid_indexed_attestation`
```python
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
2019-07-05 14:04:57 +00:00
Check if ``indexed_attestation`` has valid indices and signature.
"""
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]
if not len(bit_1_indices) == 0: # [to be removed in phase 1]
return False # [to be removed in phase 1]
# Verify max number of indices
if not len(bit_0_indices) + len(bit_1_indices) <= MAX_VALIDATORS_PER_COMMITTEE:
return False
# Verify index sets are disjoint
if not len(set(bit_0_indices).intersection(bit_1_indices)) == 0:
return False
# Verify indices are sorted
2019-07-01 01:13:27 +00:00
if not (bit_0_indices == sorted(bit_0_indices) and bit_1_indices == sorted(bit_1_indices)):
return False
# Verify aggregate signature
if not 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,
2019-09-22 19:27:42 +00:00
domain=get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch),
):
return False
return True
```
2019-06-30 09:56:14 +00:00
#### `is_valid_merkle_branch`
```python
def is_valid_merkle_branch(leaf: Hash, branch: Sequence[Hash], depth: uint64, index: uint64, root: Hash) -> bool:
2019-06-30 09:56:14 +00:00
"""
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
2019-06-30 19:49:29 +00:00
#### `compute_shuffled_index`
2019-06-30 09:56:14 +00:00
```python
2019-06-30 19:49:29 +00:00
def compute_shuffled_index(index: ValidatorIndex, index_count: uint64, seed: Hash) -> ValidatorIndex:
2019-06-30 09:56:14 +00:00
"""
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
"""
assert index < index_count
# 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)
2019-06-30 13:32:50 +00:00
source = hash(seed + int_to_bytes(current_round, length=1) + int_to_bytes(position // 256, length=4))
2019-06-30 09:56:14 +00:00
byte = source[(position % 256) // 8]
bit = (byte >> (position % 8)) % 2
index = flip if bit else index
return ValidatorIndex(index)
```
#### `compute_proposer_index`
```python
def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex:
"""
Return from ``indices`` a random index sampled by effective balance.
"""
assert len(indices) > 0
MAX_RANDOM_BYTE = 2**8 - 1
i = 0
while True:
candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)]
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
```
2019-06-30 09:56:14 +00:00
#### `compute_committee`
```python
def compute_committee(indices: Sequence[ValidatorIndex],
2019-06-30 13:11:46 +00:00
seed: Hash,
index: uint64,
count: uint64) -> Sequence[ValidatorIndex]:
2019-06-30 09:56:14 +00:00
"""
2019-06-30 13:11:46 +00:00
Return the committee corresponding to ``indices``, ``seed``, ``index``, and committee ``count``.
2019-06-30 09:56:14 +00:00
"""
start = (len(indices) * index) // count
end = (len(indices) * (index + 1)) // count
2019-06-30 19:49:29 +00:00
return [indices[compute_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
2019-06-30 09:56:14 +00:00
```
#### `compute_epoch_of_slot`
2019-06-30 09:56:14 +00:00
```python
def compute_epoch_of_slot(slot: Slot) -> Epoch:
2019-06-30 09:56:14 +00:00
"""
Return the epoch number of ``slot``.
"""
return Epoch(slot // SLOTS_PER_EPOCH)
```
#### `compute_start_slot_of_epoch`
2019-06-30 09:56:14 +00:00
```python
def compute_start_slot_of_epoch(epoch: Epoch) -> Slot:
2019-06-30 09:56:14 +00:00
"""
2019-06-30 17:42:24 +00:00
Return the start slot of ``epoch``.
2019-06-30 09:56:14 +00:00
"""
return Slot(epoch * SLOTS_PER_EPOCH)
```
#### `compute_activation_exit_epoch`
2019-06-30 09:56:14 +00:00
```python
def compute_activation_exit_epoch(epoch: Epoch) -> Epoch:
2019-06-30 09:56:14 +00:00
"""
2019-06-30 17:42:24 +00:00
Return the epoch during which validator activations and exits initiated in ``epoch`` take effect.
2019-06-30 09:56:14 +00:00
"""
return Epoch(epoch + 1 + MAX_SEED_LOOKAHEAD)
2019-06-30 09:56:14 +00:00
```
#### `compute_domain`
2019-06-30 09:56:14 +00:00
```python
def compute_domain(domain_type: DomainType, fork_version: Version=Version()) -> Domain:
2019-06-30 09:56:14 +00:00
"""
2019-06-30 23:36:19 +00:00
Return the domain for the ``domain_type`` and ``fork_version``.
2019-06-30 09:56:14 +00:00
"""
2019-06-30 20:12:02 +00:00
return Domain(domain_type + fork_version)
2019-06-30 09:56:14 +00:00
```
### Beacon state accessors
2019-06-30 09:02:18 +00:00
#### `get_current_epoch`
```python
2019-06-30 09:02:18 +00:00
def get_current_epoch(state: BeaconState) -> Epoch:
2019-01-30 09:25:39 +00:00
"""
2019-06-30 09:02:18 +00:00
Return the current epoch.
2019-01-30 09:25:39 +00:00
"""
return compute_epoch_of_slot(state.slot)
```
2019-06-30 09:02:18 +00:00
#### `get_previous_epoch`
2019-02-03 09:36:21 +00:00
```python
2019-02-12 12:24:19 +00:00
def get_previous_epoch(state: BeaconState) -> Epoch:
2019-02-03 09:36:21 +00:00
"""`
2019-06-30 13:11:46 +00:00
Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
2019-02-03 09:36:21 +00:00
"""
current_epoch = get_current_epoch(state)
return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1)
2019-02-03 09:36:21 +00:00
```
2019-06-30 09:02:18 +00:00
#### `get_block_root`
2018-09-20 05:20:49 +00:00
2019-01-26 14:31:09 +00:00
```python
2019-06-30 09:02:18 +00:00
def get_block_root(state: BeaconState, epoch: Epoch) -> Hash:
2019-01-30 09:25:39 +00:00
"""
2019-06-30 17:42:24 +00:00
Return the block root at the start of a recent ``epoch``.
2019-01-30 09:25:39 +00:00
"""
return get_block_root_at_slot(state, compute_start_slot_of_epoch(epoch))
2019-01-27 14:54:46 +00:00
```
2018-12-14 15:29:49 +00:00
2019-06-30 09:02:18 +00:00
#### `get_block_root_at_slot`
2019-04-24 04:23:51 +00:00
2018-12-12 19:00:53 +00:00
```python
2019-06-30 09:02:18 +00:00
def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Hash:
"""
2019-06-30 09:02:18 +00:00
Return the block root at a recent ``slot``.
"""
2019-06-30 09:02:18 +00:00
assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
```
2019-06-30 09:02:18 +00:00
#### `get_randao_mix`
2019-04-24 04:23:51 +00:00
2019-03-19 11:08:17 +00:00
```python
2019-06-30 09:02:18 +00:00
def get_randao_mix(state: BeaconState, epoch: Epoch) -> Hash:
2019-03-19 11:08:17 +00:00
"""
2019-06-30 09:02:18 +00:00
Return the randao mix at a recent ``epoch``.
2019-03-19 11:08:17 +00:00
"""
2019-06-30 09:02:18 +00:00
return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
2019-03-19 11:08:17 +00:00
```
2019-06-30 09:02:18 +00:00
#### `get_active_validator_indices`
2018-09-20 05:20:49 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> Sequence[ValidatorIndex]:
"""
2019-06-30 09:02:18 +00:00
Return the sequence of active validator indices at ``epoch``.
"""
2019-06-17 21:51:00 +00:00
return [ValidatorIndex(i) for i, v in enumerate(state.validators) if is_active_validator(v, epoch)]
2018-09-20 05:20:49 +00:00
```
2019-06-30 13:11:46 +00:00
#### `get_validator_churn_limit`
2019-03-21 16:04:20 +00:00
```python
2019-06-30 19:51:10 +00:00
def get_validator_churn_limit(state: BeaconState) -> uint64:
2019-03-22 04:56:54 +00:00
"""
2019-06-30 09:02:18 +00:00
Return the validator churn limit for the current epoch.
2019-03-22 04:56:54 +00:00
"""
2019-06-30 09:02:18 +00:00
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)
2019-03-21 16:04:20 +00:00
```
2019-06-30 13:11:46 +00:00
#### `get_seed`
```python
2019-09-22 19:27:42 +00:00
def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Hash:
2019-06-30 13:11:46 +00:00
"""
Return the seed at ``epoch``.
"""
mix = get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1)) # Avoid underflow
return hash(domain_type + int_to_bytes(epoch, length=8) + mix)
2019-06-30 13:11:46 +00:00
```
2019-10-13 12:52:58 +00:00
#### `get_committees_per_slot`
2019-10-13 04:53:43 +00:00
```python
2019-10-13 12:52:58 +00:00
def get_committees_per_slot(state: BeaconState, slot: Slot) -> uint64:
2019-10-13 04:53:43 +00:00
"""
2019-10-13 12:52:58 +00:00
Return the number of committees at ``slot``.
2019-10-13 04:53:43 +00:00
"""
2019-10-13 12:52:58 +00:00
epoch = compute_epoch_of_slot(slot)
return max(1, min(
2019-10-13 04:53:43 +00:00
MAX_COMMITTEES_PER_SLOT,
len(get_active_validator_indices(state, epoch)) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE,
))
```
2019-06-30 09:02:18 +00:00
#### `get_crosslink_committee`
2018-09-20 05:20:49 +00:00
```python
def get_crosslink_committee(state: BeaconState, slot: Slot, index: uint64) -> Sequence[ValidatorIndex]:
"""
2019-10-13 12:52:58 +00:00
Return the crosslink committee at ``slot`` for ``index``.
2019-06-30 09:02:18 +00:00
"""
epoch = compute_epoch_of_slot(slot)
2019-10-13 12:52:58 +00:00
committees_per_slot = get_committees_per_slot(state, slot)
2019-10-13 04:53:43 +00:00
slot_start_index = get_slot_start_index(state, slot)
slot_offset = (index + MAX_COMMITTEES_PER_SLOT - slot_start_index) % MAX_COMMITTEES_PER_SLOT
epoch_offset = slot_offset + (slot % SLOTS_PER_EPOCH) * committees_per_slot
2019-06-30 09:02:18 +00:00
return compute_committee(
indices=get_active_validator_indices(state, epoch),
2019-09-22 19:27:42 +00:00
seed=get_seed(state, epoch, DOMAIN_BEACON_ATTESTER),
2019-10-13 04:53:43 +00:00
index=epoch_offset,
2019-10-13 12:52:58 +00:00
count=committees_per_slot * SLOTS_PER_EPOCH,
2019-06-30 09:02:18 +00:00
)
```
2019-10-13 04:53:43 +00:00
#### `get_slot_start_index`
```python
def get_slot_start_index(state: BeaconState, slot: Slot) -> uint64:
"""
Return the start index of the 0th committee at ``slot``.
"""
epoch = compute_epoch_of_slot(slot)
2019-10-13 12:52:58 +00:00
committees_per_slot = get_committees_per_slot(state, slot)
start_index = get_start_index(state, epoch)
slot_start_index = ((slot % SLOTS_PER_EPOCH) * committees_per_slot + start_index) % MAX_COMMITTEES_PER_SLOT
2019-10-13 04:53:43 +00:00
return slot_start_index
```
#### `get_start_index`
```python
def get_start_index(state: BeaconState, epoch: Epoch) -> uint64:
"""
Return the start index of the 0th committee at ``epoch``.
"""
assert epoch <= get_current_epoch(state) + 1
check_epoch = Epoch(get_current_epoch(state) + 1)
index = (state.start_index + get_index_delta(state, get_current_epoch(state))) % MAX_COMMITTEES_PER_SLOT
MAX_COMMITTEES_PER_EPOCH = MAX_COMMITTEES_PER_SLOT * SLOTS_PER_EPOCH
while check_epoch > epoch:
check_epoch -= Epoch(1)
index = (index + MAX_COMMITTEES_PER_EPOCH - get_index_delta(state, check_epoch)) % MAX_COMMITTEES_PER_SLOT
return index
```
#### `get_index_delta`
```python
def get_index_delta(state: BeaconState, epoch: Epoch) -> uint64:
"""
Return the amount to increase ``state.start_index`` at ``epoch``.
"""
2019-10-13 12:52:58 +00:00
return get_committees_per_slot(state, compute_start_slot_of_epoch(epoch)) * SLOTS_PER_EPOCH
2019-10-13 04:53:43 +00:00
```
2019-06-30 17:42:24 +00:00
#### `get_beacon_proposer_index`
2019-03-04 18:45:41 +00:00
```python
2019-06-30 17:42:24 +00:00
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
2019-03-04 18:45:41 +00:00
"""
2019-06-30 17:42:24 +00:00
Return the beacon proposer index at the current slot.
2019-03-04 18:45:41 +00:00
"""
2019-06-30 09:02:18 +00:00
epoch = get_current_epoch(state)
2019-09-22 19:27:42 +00:00
seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + int_to_bytes(state.slot, length=8))
indices = get_active_validator_indices(state, epoch)
return compute_proposer_index(state, indices, seed)
2019-03-04 18:45:41 +00:00
```
2018-09-20 05:20:49 +00:00
2019-06-30 09:02:18 +00:00
#### `get_total_balance`
```python
2019-06-30 09:02:18 +00:00
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
"""
2019-06-30 09:02:18 +00:00
Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
"""
2019-07-05 14:03:37 +00:00
return Gwei(max(1, sum([state.validators[index].effective_balance for index in indices])))
2019-06-30 09:02:18 +00:00
```
2019-06-30 13:11:46 +00:00
#### `get_total_active_balance`
```python
def get_total_active_balance(state: BeaconState) -> Gwei:
"""
Return the combined effective balance of the active validators.
"""
return get_total_balance(state, set(get_active_validator_indices(state, get_current_epoch(state))))
```
2019-06-30 09:02:18 +00:00
#### `get_domain`
```python
2019-06-30 20:12:02 +00:00
def get_domain(state: BeaconState, domain_type: DomainType, message_epoch: Epoch=None) -> Domain:
2019-06-30 09:02:18 +00:00
"""
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 compute_domain(domain_type, fork_version)
2019-06-30 09:02:18 +00:00
```
#### `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,
)
```
2019-06-30 09:02:18 +00:00
#### `get_attesting_indices`
```python
2019-06-30 09:02:18 +00:00
def get_attesting_indices(state: BeaconState,
data: AttestationData,
bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]) -> Set[ValidatorIndex]:
"""
2019-06-30 09:02:18 +00:00
Return the set of attesting indices corresponding to ``data`` and ``bits``.
"""
committee = get_crosslink_committee(state, data.slot, data.index)
2019-06-30 09:02:18 +00:00
return set(index for i, index in enumerate(committee) if bits[i])
```
2019-06-30 10:01:54 +00:00
### Beacon state mutators
2018-09-20 05:20:49 +00:00
2019-06-30 09:02:18 +00:00
#### `increase_balance`
2019-02-07 21:12:58 +00:00
```python
2019-06-30 09:02:18 +00:00
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
"""
2019-06-30 09:56:14 +00:00
Increase the validator balance at index ``index`` by ``delta``.
2019-06-30 09:02:18 +00:00
"""
state.balances[index] += delta
2019-02-07 21:12:58 +00:00
```
2018-09-20 05:20:49 +00:00
2019-06-30 09:02:18 +00:00
#### `decrease_balance`
2019-02-03 10:14:02 +00:00
```python
2019-06-30 09:02:18 +00:00
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
2019-02-03 10:14:02 +00:00
"""
2019-06-30 09:56:14 +00:00
Decrease the validator balance at index ``index`` by ``delta``, with underflow protection.
2019-02-03 10:14:02 +00:00
"""
2019-06-30 09:02:18 +00:00
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
2019-02-03 10:14:02 +00:00
```
#### `initiate_validator_exit`
2018-12-10 21:16:06 +00:00
```python
2019-01-19 07:58:24 +00:00
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
2019-01-30 09:25:39 +00:00
"""
2019-06-30 09:56:14 +00:00
Initiate the exit of the validator with index ``index``.
2019-01-30 09:25:39 +00:00
"""
2019-04-14 09:01:53 +00:00
# Return if validator already initiated exit
2019-06-09 19:41:21 +00:00
validator = state.validators[index]
2019-04-13 23:13:53 +00:00
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return
2019-04-14 09:01:53 +00:00
# Compute exit queue epoch
2019-06-09 19:41:21 +00:00
exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
exit_queue_epoch = max(exit_epochs + [compute_activation_exit_epoch(get_current_epoch(state))])
2019-06-09 19:41:21 +00:00
exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch])
2019-06-30 13:11:46 +00:00
if exit_queue_churn >= get_validator_churn_limit(state):
exit_queue_epoch += Epoch(1)
2018-12-11 15:49:50 +00:00
2019-04-13 23:13:53 +00:00
# Set validator exit epoch and withdrawable epoch
2019-04-14 08:10:44 +00:00
validator.exit_epoch = exit_queue_epoch
validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
```
2019-02-12 12:24:19 +00:00
#### `slash_validator`
```python
def slash_validator(state: BeaconState,
slashed_index: ValidatorIndex,
whistleblower_index: ValidatorIndex=None) -> None:
2019-01-30 09:25:39 +00:00
"""
Slash the validator with index ``slashed_index``.
2019-01-30 09:25:39 +00:00
"""
epoch = get_current_epoch(state)
2019-03-29 07:26:26 +00:00
initiate_validator_exit(state, slashed_index)
validator = state.validators[slashed_index]
validator.slashed = True
validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR))
state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT)
# Apply proposer and whistleblower rewards
2019-06-30 17:42:24 +00:00
proposer_index = get_beacon_proposer_index(state)
if whistleblower_index is None:
whistleblower_index = proposer_index
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
increase_balance(state, proposer_index, proposer_reward)
increase_balance(state, whistleblower_index, whistleblower_reward - proposer_reward)
```
2019-05-05 16:15:05 +00:00
## Genesis
2018-09-20 05:20:49 +00:00
2019-06-30 09:56:14 +00:00
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:
2019-05-05 16:15:05 +00:00
2019-06-30 19:25:58 +00:00
- `eth1_block_hash` is the hash of the Ethereum 1.0 block
- `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`
2019-03-03 11:04:28 +00:00
```python
def initialize_beacon_state_from_eth1(eth1_block_hash: Hash,
eth1_timestamp: uint64,
deposits: Sequence[Deposit]) -> BeaconState:
state = BeaconState(
2019-06-29 20:53:04 +00:00
genesis_time=eth1_timestamp - eth1_timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY,
2019-06-29 21:06:17 +00:00
eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)),
latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
)
2018-10-09 07:33:22 +00:00
# Process deposits
leaves = list(map(lambda deposit: deposit.data, deposits))
2019-06-29 20:29:10 +00:00
for index, deposit in enumerate(deposits):
2019-06-30 13:32:50 +00:00
deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
2019-02-15 00:23:03 +00:00
process_deposit(state, deposit)
2018-12-10 21:16:06 +00:00
2019-06-29 20:29:10 +00:00
# Process activations
2019-06-29 20:36:27 +00:00
for index, validator in enumerate(state.validators):
2019-06-30 20:27:01 +00:00
balance = state.balances[index]
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = GENESIS_EPOCH
validator.activation_epoch = GENESIS_EPOCH
2018-12-10 21:16:06 +00:00
return state
```
2018-09-20 05:20:49 +00:00
2019-06-30 09:56:14 +00:00
### Genesis state
Let `genesis_state = candidate_state` whenever `is_valid_genesis_state(candidate_state) is True` for the first time.
```python
def is_valid_genesis_state(state: BeaconState) -> bool:
if state.genesis_time < MIN_GENESIS_TIME:
return False
2019-06-30 09:56:14 +00:00
if len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
return False
2019-06-30 09:56:14 +00:00
return True
```
2019-06-30 09:56:14 +00:00
*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.
2019-05-05 16:15:05 +00:00
### Genesis block
Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`.
## Beacon chain state transition function
2019-06-30 19:25:58 +00:00
The post-state corresponding to a pre-state `state` and a block `block` is defined as `state_transition(state, block)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid.
2019-05-01 12:14:10 +00:00
```python
2019-05-13 20:53:28 +00:00
def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
2019-05-08 18:15:23 +00:00
# Process slots (including those with no blocks) since block
process_slots(state, block.slot)
# Process block
process_block(state, block)
2019-05-14 05:15:03 +00:00
# Validate state root (`validate_state_root == True` in production)
2019-05-13 20:53:28 +00:00
if validate_state_root:
2019-05-14 05:15:03 +00:00
assert block.state_root == hash_tree_root(state)
2019-05-08 18:15:23 +00:00
# Return post-state
2019-05-02 10:07:25 +00:00
return state
2019-05-01 12:14:10 +00:00
```
2018-09-20 05:20:49 +00:00
2019-05-03 20:21:42 +00:00
```python
def process_slots(state: BeaconState, slot: Slot) -> None:
assert state.slot <= slot
2019-05-03 20:21:42 +00:00
while state.slot < slot:
process_slot(state)
2019-06-30 17:42:24 +00:00
# Process epoch on the start slot of the next epoch
2019-05-03 20:21:42 +00:00
if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
process_epoch(state)
state.slot += Slot(1)
2019-05-03 20:21:42 +00:00
```
2019-03-03 11:04:28 +00:00
```python
2019-05-03 20:21:42 +00:00
def process_slot(state: BeaconState) -> None:
# Cache state root
2019-05-01 13:16:55 +00:00
previous_state_root = hash_tree_root(state)
2019-06-09 19:41:21 +00:00
state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
2019-05-03 20:21:42 +00:00
# Cache latest block header state root
if state.latest_block_header.state_root == Bytes32():
2019-05-01 13:16:55 +00:00
state.latest_block_header.state_root = previous_state_root
2019-05-03 20:21:42 +00:00
# Cache block root
2019-05-01 14:07:55 +00:00
previous_block_root = signing_root(state.latest_block_header)
2019-06-09 19:41:21 +00:00
state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
2019-03-03 11:04:28 +00:00
```
2018-09-20 05:20:49 +00:00
2019-05-01 12:29:03 +00:00
### Epoch processing
*Note*: The `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
2019-05-01 12:14:10 +00:00
```python
2019-05-01 12:29:03 +00:00
def process_epoch(state: BeaconState) -> None:
2019-05-01 12:14:10 +00:00
process_justification_and_finalization(state)
process_rewards_and_penalties(state)
process_registry_updates(state)
2019-05-24 14:51:21 +00:00
# @process_reveal_deadlines
# @process_challenge_deadlines
2019-05-01 12:14:10 +00:00
process_slashings(state)
2019-08-24 11:55:35 +00:00
# @update_period_committee
2019-05-01 12:14:10 +00:00
process_final_updates(state)
2019-05-24 14:51:21 +00:00
# @after_process_final_updates
2019-05-01 12:14:10 +00:00
```
2019-03-07 19:05:34 +00:00
#### Helper functions
```python
2019-06-22 16:12:42 +00:00
def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
2019-06-23 09:09:09 +00:00
assert epoch in (get_previous_epoch(state), get_current_epoch(state))
2019-04-20 05:17:33 +00:00
return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations
2019-03-07 19:05:34 +00:00
```
2019-03-03 11:04:28 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_matching_target_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
2019-03-07 19:05:34 +00:00
return [
2019-04-20 05:17:33 +00:00
a for a in get_matching_source_attestations(state, epoch)
2019-06-22 20:49:53 +00:00
if a.data.target.root == get_block_root(state, epoch)
2019-03-07 19:05:34 +00:00
]
2019-03-03 11:04:28 +00:00
```
2019-03-07 19:05:34 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
2019-03-07 19:05:34 +00:00
return [
2019-04-20 05:17:33 +00:00
a for a in get_matching_source_attestations(state, epoch)
if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot)
2019-03-07 19:05:34 +00:00
]
```
2019-03-07 19:05:34 +00:00
```python
def get_unslashed_attesting_indices(state: BeaconState,
2019-06-22 16:12:42 +00:00
attestations: Sequence[PendingAttestation]) -> Set[ValidatorIndex]:
2019-06-30 13:11:46 +00:00
output = set() # type: Set[ValidatorIndex]
for a in attestations:
2019-06-28 11:23:22 +00:00
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
return set(filter(lambda index: not state.validators[index].slashed, output))
2019-03-07 19:05:34 +00:00
```
2018-11-16 15:48:57 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_attesting_balance(state: BeaconState, attestations: Sequence[PendingAttestation]) -> Gwei:
return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
```
#### Justification and finalization
2019-03-07 19:05:34 +00:00
```python
def process_justification_and_finalization(state: BeaconState) -> None:
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
2019-04-11 12:28:42 +00:00
return
2019-04-20 06:10:25 +00:00
previous_epoch = get_previous_epoch(state)
current_epoch = get_current_epoch(state)
old_previous_justified_checkpoint = state.previous_justified_checkpoint
old_current_justified_checkpoint = state.current_justified_checkpoint
2019-03-12 18:32:11 +00:00
# Process justifications
state.previous_justified_checkpoint = state.current_justified_checkpoint
state.justification_bits[1:] = state.justification_bits[:-1]
2019-06-28 14:26:02 +00:00
state.justification_bits[0] = 0b0
2019-06-28 11:34:01 +00:00
matching_target_attestations = get_matching_target_attestations(state, previous_epoch) # Previous epoch
if get_attesting_balance(state, matching_target_attestations) * 3 >= get_total_active_balance(state) * 2:
2019-06-25 03:43:05 +00:00
state.current_justified_checkpoint = Checkpoint(epoch=previous_epoch,
root=get_block_root(state, previous_epoch))
2019-06-28 11:23:22 +00:00
state.justification_bits[1] = 0b1
2019-06-28 11:34:01 +00:00
matching_target_attestations = get_matching_target_attestations(state, current_epoch) # Current epoch
if get_attesting_balance(state, matching_target_attestations) * 3 >= get_total_active_balance(state) * 2:
state.current_justified_checkpoint = Checkpoint(epoch=current_epoch,
root=get_block_root(state, current_epoch))
2019-06-28 11:23:22 +00:00
state.justification_bits[0] = 0b1
2019-03-07 19:05:34 +00:00
# Process finalizations
2019-06-28 11:23:22 +00:00
bits = state.justification_bits
# The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
2019-06-28 11:23:22 +00:00
if all(bits[1:4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint
# The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
2019-06-28 11:23:22 +00:00
if all(bits[1:3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint
# The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
2019-06-28 11:23:22 +00:00
if all(bits[0:3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint
# The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
2019-06-28 11:23:22 +00:00
if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint
```
2018-09-20 05:20:49 +00:00
#### Rewards and penalties
```python
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
total_balance = get_total_active_balance(state)
2019-06-09 19:41:21 +00:00
effective_balance = state.validators[index].effective_balance
return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH)
```
```python
2019-06-22 16:12:42 +00:00
def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2019-04-20 06:10:25 +00:00
previous_epoch = get_previous_epoch(state)
total_balance = get_total_active_balance(state)
2019-06-17 21:51:00 +00:00
rewards = [Gwei(0) for _ in range(len(state.validators))]
penalties = [Gwei(0) for _ in range(len(state.validators))]
2019-04-24 04:23:51 +00:00
eligible_validator_indices = [
2019-06-17 21:51:00 +00:00
ValidatorIndex(index) for index, v in enumerate(state.validators)
2019-04-24 04:23:51 +00:00
if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)
]
2019-04-24 04:23:51 +00:00
# Micro-incentives for matching FFG source, FFG target, and head
matching_source_attestations = get_matching_source_attestations(state, previous_epoch)
matching_target_attestations = get_matching_target_attestations(state, previous_epoch)
matching_head_attestations = get_matching_head_attestations(state, previous_epoch)
for attestations in (matching_source_attestations, matching_target_attestations, matching_head_attestations):
unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations)
2019-06-02 20:13:52 +00:00
attesting_balance = get_total_balance(state, unslashed_attesting_indices)
2019-04-24 04:23:51 +00:00
for index in eligible_validator_indices:
if index in unslashed_attesting_indices:
rewards[index] += get_base_reward(state, index) * attesting_balance // total_balance
else:
2019-04-24 04:23:51 +00:00
penalties[index] += get_base_reward(state, index)
# Proposer and inclusion delay micro-rewards
2019-04-24 05:32:43 +00:00
for index in get_unslashed_attesting_indices(state, matching_source_attestations):
2019-04-30 11:27:45 +00:00
attestation = min([
2019-05-03 16:34:16 +00:00
a for a in matching_source_attestations
2019-06-28 11:23:22 +00:00
if index in get_attesting_indices(state, a.data, a.aggregation_bits)
2019-04-30 11:27:45 +00:00
], key=lambda a: a.inclusion_delay)
2019-06-18 14:24:23 +00:00
proposer_reward = Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT)
Tweak inclusion delay rewards and set BASE_REWARD_FACTOR Substantive changes: 1) Split the inclusion delay reward between attester and proposer to add up to at most one base reward. This is analogous to the reward logic in `slash_validator`, and makes the `BASE_REWARDS_PER_EPOCH` constant include proposer rewards. 2) Double `BASE_REWARD_FACTOR` to 2^6 (addressing item 4 in #1054). When the total effective balance is 2^17 ETH then maximum annual issuance is a bit below 2^21 ETH. Maximum annual issuance happens when a) all validators make perfect attestations (matching source, target, head, as well as consistent crosslink data), b) all attestations are included as fast as possible (in particular, no skip blocks), and c) there are no slashings. ```python BASE_REWARD_FACTOR = 2**6 SLOTS_PER_EPOCH = 2**6 SECONDS_PER_SLOT = 6 BASE_REWARDS_PER_EPOCH = 5 GWEI_PER_ETH = 10**9 MAX_TOTAL_EFFECTIVE_BALANCE = 2**27 * GWEI_PER_ETH TARGET_MAX_ISSUANCE = 2**21 * GWEI_PER_ETH 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 MAX_REWARDS_PER_EPOCH = MAX_TOTAL_EFFECTIVE_BALANCE * BASE_REWARD_FACTOR // integer_squareroot(MAX_TOTAL_EFFECTIVE_BALANCE) // BASE_REWARDS_PER_EPOCH EPOCHS_PER_YEAR = 365.25*24*60*60 / (SECONDS_PER_SLOT * SLOTS_PER_EPOCH) MAX_REWARDS_PER_YEAR = EPOCHS_PER_YEAR * MAX_REWARDS_PER_EPOCH * BASE_REWARDS_PER_EPOCH print(MAX_REWARDS_PER_YEAR / TARGET_MAX_ISSUANCE) ```
2019-06-10 14:14:32 +00:00
rewards[attestation.proposer_index] += proposer_reward
max_attester_reward = get_base_reward(state, index) - proposer_reward
2019-07-01 03:34:35 +00:00
rewards[index] += Gwei(
max_attester_reward
* (SLOTS_PER_EPOCH + MIN_ATTESTATION_INCLUSION_DELAY - attestation.inclusion_delay)
// SLOTS_PER_EPOCH
)
2019-04-24 04:23:51 +00:00
# Inactivity penalty
finality_delay = previous_epoch - state.finalized_checkpoint.epoch
2019-04-24 04:23:51 +00:00
if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY:
matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations)
for index in eligible_validator_indices:
penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index))
2019-04-24 04:23:51 +00:00
if index not in matching_target_attesting_indices:
penalties[index] += Gwei(
2019-06-09 19:41:21 +00:00
state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
)
return rewards, penalties
```
2018-09-20 05:20:49 +00:00
```python
def process_rewards_and_penalties(state: BeaconState) -> None:
2019-04-11 12:28:42 +00:00
if get_current_epoch(state) == GENESIS_EPOCH:
return
2019-04-20 05:17:33 +00:00
rewards1, penalties1 = get_attestation_deltas(state)
2019-06-17 21:51:00 +00:00
for index in range(len(state.validators)):
increase_balance(state, ValidatorIndex(index), rewards1[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index])
```
2018-11-23 04:54:11 +00:00
#### Registry updates
2018-12-05 11:22:15 +00:00
```python
def process_registry_updates(state: BeaconState) -> None:
# Process activation eligibility and ejections
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
if (
2019-06-30 20:59:12 +00:00
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
and validator.effective_balance == MAX_EFFECTIVE_BALANCE
):
validator.activation_eligibility_epoch = get_current_epoch(state)
2019-04-20 06:32:41 +00:00
if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE:
initiate_validator_exit(state, ValidatorIndex(index))
2019-03-07 19:05:34 +00:00
2019-04-22 05:16:34 +00:00
# Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
activation_queue = sorted([
2019-06-30 20:59:12 +00:00
index for index, validator in enumerate(state.validators)
if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH
and validator.activation_epoch >= compute_activation_exit_epoch(state.finalized_checkpoint.epoch)
2019-06-09 19:41:21 +00:00
], key=lambda index: state.validators[index].activation_eligibility_epoch)
# Dequeued validators for activation up to churn limit (without resetting activation epoch)
2019-06-30 13:11:46 +00:00
for index in activation_queue[:get_validator_churn_limit(state)]:
2019-06-09 19:41:21 +00:00
validator = state.validators[index]
if validator.activation_epoch == FAR_FUTURE_EPOCH:
validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
2019-03-07 19:05:34 +00:00
```
2019-04-06 10:07:03 +00:00
#### Slashings
2019-03-07 19:05:34 +00:00
```python
def process_slashings(state: BeaconState) -> None:
2019-06-22 05:34:02 +00:00
epoch = get_current_epoch(state)
total_balance = get_total_active_balance(state)
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow
penalty_numerator = validator.effective_balance // increment * min(sum(state.slashings) * 3, total_balance)
penalty = penalty_numerator // total_balance * increment
decrease_balance(state, ValidatorIndex(index), penalty)
2019-03-07 19:05:34 +00:00
```
#### Final updates
```python
def process_final_updates(state: BeaconState) -> None:
2019-03-07 19:05:34 +00:00
current_epoch = get_current_epoch(state)
2019-06-30 10:01:54 +00:00
next_epoch = Epoch(current_epoch + 1)
# Reset eth1 data votes
if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
state.eth1_data_votes = []
# Update effective balances with hysteresis
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
balance = state.balances[index]
HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance:
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
# Reset slashings
state.slashings[next_epoch % EPOCHS_PER_SLASHINGS_VECTOR] = Gwei(0)
2019-03-07 19:05:34 +00:00
# Set randao mix
state.randao_mixes[next_epoch % EPOCHS_PER_HISTORICAL_VECTOR] = get_randao_mix(state, current_epoch)
2019-03-07 19:05:34 +00:00
# Set historical root accumulator
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
2019-06-30 13:45:36 +00:00
historical_batch = HistoricalBatch(block_roots=state.block_roots, state_roots=state.state_roots)
2019-03-08 17:13:05 +00:00
state.historical_roots.append(hash_tree_root(historical_batch))
2019-10-13 04:53:43 +00:00
# Update start shard
state.start_index = (state.start_index + get_index_delta(state, current_epoch)) % MAX_COMMITTEES_PER_SLOT
2019-03-07 19:05:34 +00:00
# Rotate current/previous epoch attestations
state.previous_epoch_attestations = state.current_epoch_attestations
state.current_epoch_attestations = []
```
2019-05-01 12:29:03 +00:00
### Block processing
2019-03-07 19:05:34 +00:00
```python
2019-05-01 12:14:10 +00:00
def process_block(state: BeaconState, block: BeaconBlock) -> None:
process_block_header(state, block)
2019-05-03 20:21:42 +00:00
process_randao(state, block.body)
process_eth1_data(state, block.body)
2019-05-01 12:14:10 +00:00
process_operations(state, block.body)
2019-03-07 19:05:34 +00:00
```
#### Block header
```python
def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
# Verify that the slots match
assert block.slot == state.slot
# Verify that the parent matches
2019-05-06 19:49:46 +00:00
assert block.parent_root == signing_root(state.latest_block_header)
2019-03-07 19:05:34 +00:00
# Save current block as the new latest block
2019-04-19 08:26:54 +00:00
state.latest_block_header = BeaconBlockHeader(
slot=block.slot,
2019-05-06 19:49:46 +00:00
parent_root=block.parent_root,
# `state_root` is zeroed and overwritten in the next `process_slot` call
2019-05-07 07:52:56 +00:00
body_root=hash_tree_root(block.body),
# `signature` is zeroed
2019-04-19 08:26:54 +00:00
)
2019-03-17 11:48:47 +00:00
# Verify proposer is not slashed
2019-06-30 17:42:24 +00:00
proposer = state.validators[get_beacon_proposer_index(state)]
2019-03-11 22:07:34 +00:00
assert not proposer.slashed
# Verify proposer signature
assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
2019-03-07 19:05:34 +00:00
```
#### RANDAO
```python
2019-05-03 20:21:42 +00:00
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
epoch = get_current_epoch(state)
# Verify RANDAO reveal
2019-06-30 17:42:24 +00:00
proposer = state.validators[get_beacon_proposer_index(state)]
assert bls_verify(proposer.pubkey, hash_tree_root(epoch), body.randao_reveal, get_domain(state, DOMAIN_RANDAO))
# Mix in RANDAO reveal
mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
2019-03-07 19:05:34 +00:00
```
#### Eth1 data
```python
2019-05-03 20:21:42 +00:00
def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
state.eth1_data_votes.append(body.eth1_data)
if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD:
2019-06-09 19:41:21 +00:00
state.eth1_data = body.eth1_data
2019-03-07 19:05:34 +00:00
```
#### Operations
2019-03-07 19:05:34 +00:00
```python
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
2019-05-03 20:21:42 +00:00
# Verify that outstanding deposits are processed up to the maximum number of deposits
2019-06-09 19:41:21 +00:00
assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
2019-05-03 20:21:42 +00:00
# Verify that there are no duplicate transfers
assert len(body.transfers) == len(set(body.transfers))
2019-06-18 00:54:08 +00:00
2019-06-30 15:10:22 +00:00
for operations, function in (
(body.proposer_slashings, process_proposer_slashing),
(body.attester_slashings, process_attester_slashing),
(body.attestations, process_attestation),
(body.deposits, process_deposit),
(body.voluntary_exits, process_voluntary_exit),
(body.transfers, process_transfer),
2019-08-24 11:55:18 +00:00
# @process_shard_receipt_proofs
2019-06-30 15:10:22 +00:00
):
for operation in operations:
function(state, operation)
```
2019-03-07 19:05:34 +00:00
##### Proposer slashings
2019-03-07 19:05:34 +00:00
```python
2019-05-03 20:21:42 +00:00
def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
2019-06-09 19:41:21 +00:00
proposer = state.validators[proposer_slashing.proposer_index]
# Verify slots match
assert proposer_slashing.header_1.slot == proposer_slashing.header_2.slot
2019-03-08 17:34:51 +00:00
# But the headers are different
assert proposer_slashing.header_1 != proposer_slashing.header_2
2019-03-19 11:08:17 +00:00
# Check proposer is slashable
2019-03-19 11:12:50 +00:00
assert is_slashable_validator(proposer, get_current_epoch(state))
2019-03-07 19:05:34 +00:00
# Signatures are valid
for header in (proposer_slashing.header_1, proposer_slashing.header_2):
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_of_slot(header.slot))
assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain)
2019-03-07 19:05:34 +00:00
slash_validator(state, proposer_slashing.proposer_index)
```
##### Attester slashings
2018-12-10 21:16:06 +00:00
2019-03-02 01:49:28 +00:00
```python
2019-05-03 20:21:42 +00:00
def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
2019-04-30 09:39:18 +00:00
attestation_1 = attester_slashing.attestation_1
attestation_2 = attester_slashing.attestation_2
2019-05-01 06:42:49 +00:00
assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
assert is_valid_indexed_attestation(state, attestation_1)
assert is_valid_indexed_attestation(state, attestation_2)
2019-05-01 06:42:49 +00:00
slashed_any = False
2019-04-30 09:39:18 +00:00
attesting_indices_1 = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
attesting_indices_2 = attestation_2.custody_bit_0_indices + attestation_2.custody_bit_1_indices
for index in sorted(set(attesting_indices_1).intersection(attesting_indices_2)):
2019-06-09 19:41:21 +00:00
if is_slashable_validator(state.validators[index], get_current_epoch(state)):
2019-05-01 06:42:49 +00:00
slash_validator(state, index)
slashed_any = True
assert slashed_any
2019-03-02 01:49:28 +00:00
```
2019-03-07 19:05:34 +00:00
##### Attestations
2019-01-08 00:53:33 +00:00
```python
2019-03-07 19:05:34 +00:00
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
2019-05-05 18:30:55 +00:00
data = attestation.data
2019-10-13 04:53:43 +00:00
assert data.index < MAX_COMMITTEES_PER_SLOT
2019-10-13 12:52:58 +00:00
slot_start_index = get_slot_start_index(state, data.slot)
if data.index < slot_start_index:
test_index = data.index + MAX_COMMITTEES_PER_SLOT
else:
test_index = data.index
assert slot_start_index <= test_index < slot_start_index + get_committees_per_slot(state, data.slot)
2019-06-22 20:49:53 +00:00
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
committee = get_crosslink_committee(state, data.slot, data.index)
2019-07-25 18:32:56 +00:00
assert len(attestation.aggregation_bits) == len(attestation.custody_bits) == len(committee)
2019-07-22 13:13:07 +00:00
2019-03-07 19:05:34 +00:00
pending_attestation = PendingAttestation(
2019-04-03 19:40:54 +00:00
data=data,
2019-06-28 11:23:22 +00:00
aggregation_bits=attestation.aggregation_bits,
inclusion_delay=state.slot - data.slot,
2019-06-30 17:42:24 +00:00
proposer_index=get_beacon_proposer_index(state),
2019-03-07 19:05:34 +00:00
)
2019-05-05 11:04:34 +00:00
2019-06-22 20:49:53 +00:00
if data.target.epoch == get_current_epoch(state):
2019-06-23 09:18:24 +00:00
assert data.source == state.current_justified_checkpoint
2019-03-07 19:05:34 +00:00
state.current_epoch_attestations.append(pending_attestation)
else:
2019-06-23 09:18:24 +00:00
assert data.source == state.previous_justified_checkpoint
2019-03-07 19:05:34 +00:00
state.previous_epoch_attestations.append(pending_attestation)
2019-05-05 11:04:34 +00:00
2019-06-23 09:18:24 +00:00
# Check signature
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
2019-02-12 12:24:19 +00:00
```
2019-03-07 19:05:34 +00:00
##### Deposits
```python
def process_deposit(state: BeaconState, deposit: Deposit) -> None:
# Verify the Merkle branch
2019-06-30 09:11:23 +00:00
assert is_valid_merkle_branch(
leaf=hash_tree_root(deposit.data),
2019-06-30 09:02:18 +00:00
branch=deposit.proof,
2019-06-30 10:01:54 +00:00
depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the `List` length mix-in
2019-06-09 19:41:21 +00:00
index=state.eth1_deposit_index,
root=state.eth1_data.deposit_root,
)
2019-04-20 06:35:02 +00:00
# Deposits must be processed in order
2019-06-09 19:41:21 +00:00
state.eth1_deposit_index += 1
pubkey = deposit.data.pubkey
amount = deposit.data.amount
2019-06-09 19:41:21 +00:00
validator_pubkeys = [v.pubkey for v in state.validators]
if pubkey not in validator_pubkeys:
2019-06-30 13:11:46 +00:00
# Verify the deposit signature (proof of possession) for new validators.
# Note: The deposit contract does not check signatures.
# Note: Deposits are valid across forks, thus the deposit domain is retrieved directly from `compute_domain`.
domain = compute_domain(DOMAIN_DEPOSIT)
2019-06-30 19:49:29 +00:00
if not bls_verify(pubkey, signing_root(deposit.data), deposit.data.signature, domain):
return
# Add validator and balance entries
2019-06-09 19:41:21 +00:00
state.validators.append(Validator(
pubkey=pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
activation_epoch=FAR_FUTURE_EPOCH,
exit_epoch=FAR_FUTURE_EPOCH,
withdrawable_epoch=FAR_FUTURE_EPOCH,
effective_balance=min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE),
))
2019-04-20 05:17:33 +00:00
state.balances.append(amount)
else:
# Increase balance by deposit amount
index = ValidatorIndex(validator_pubkeys.index(pubkey))
increase_balance(state, index, amount)
```
2019-03-07 19:05:34 +00:00
##### Voluntary exits
2019-02-12 12:24:19 +00:00
```python
2019-03-10 12:50:28 +00:00
def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
2019-06-09 19:41:21 +00:00
validator = state.validators[exit.validator_index]
2019-03-19 21:49:01 +00:00
# Verify the validator is active
assert is_active_validator(validator, get_current_epoch(state))
2019-03-07 19:05:34 +00:00
# Verify the validator has not yet exited
assert validator.exit_epoch == FAR_FUTURE_EPOCH
2019-03-07 19:05:34 +00:00
# Exits must specify an epoch when they become valid; they are not valid before then
assert get_current_epoch(state) >= exit.epoch
2019-03-19 20:43:05 +00:00
# Verify the validator has been active long enough
assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
2019-03-07 19:05:34 +00:00
# Verify signature
domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain)
2019-03-19 20:43:05 +00:00
# Initiate exit
2019-03-07 19:05:34 +00:00
initiate_validator_exit(state, exit.validator_index)
```
2019-03-07 19:05:34 +00:00
##### Transfers
2018-09-20 05:20:49 +00:00
2019-03-02 01:49:28 +00:00
```python
2019-03-07 19:05:34 +00:00
def process_transfer(state: BeaconState, transfer: Transfer) -> None:
# 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)
2019-03-07 19:05:34 +00:00
# A transfer is valid in only one slot
assert state.slot == transfer.slot
2019-06-30 13:11:46 +00:00
# Sender must satisfy at least one of the following:
2019-03-07 19:05:34 +00:00
assert (
2019-06-30 13:11:46 +00:00
# 1) Never have been eligible for activation
2019-06-09 19:41:21 +00:00
state.validators[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
2019-06-30 13:11:46 +00:00
# 2) Be withdrawable
2019-06-09 19:41:21 +00:00
get_current_epoch(state) >= state.validators[transfer.sender].withdrawable_epoch or
2019-06-30 13:11:46 +00:00
# 3) Have a balance of at least MAX_EFFECTIVE_BALANCE after the transfer
state.balances[transfer.sender] >= transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE
2019-03-02 01:49:28 +00:00
)
2019-03-07 19:05:34 +00:00
# Verify that the pubkey is valid
2019-06-30 19:56:55 +00:00
assert state.validators[transfer.sender].withdrawal_credentials == BLS_WITHDRAWAL_PREFIX + hash(transfer.pubkey)[1:]
2019-03-07 19:05:34 +00:00
# Verify that the signature is valid
assert bls_verify(transfer.pubkey, signing_root(transfer), transfer.signature, get_domain(state, DOMAIN_TRANSFER))
2019-03-07 19:05:34 +00:00
# Process the transfer
decrease_balance(state, transfer.sender, transfer.amount + transfer.fee)
increase_balance(state, transfer.recipient, transfer.amount)
2019-06-30 17:42:24 +00:00
increase_balance(state, get_beacon_proposer_index(state), transfer.fee)
# Verify balances are not dust
2019-04-20 05:17:33 +00:00
assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT)
assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT)
2019-03-02 01:49:28 +00:00
```