2018-11-14 21:01:57 +00:00
# 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 -->
2019-12-10 14:17:06 +00:00
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE - RUN doctoc TO UPDATE -->
2018-12-01 05:29:19 +00:00
2019-12-10 14:17:06 +00:00
- [Introduction ](#introduction )
- [Notation ](#notation )
- [Custom types ](#custom-types )
- [Constants ](#constants )
- [Configuration ](#configuration )
- [Misc ](#misc )
- [Gwei values ](#gwei-values )
- [Initial values ](#initial-values )
- [Time parameters ](#time-parameters )
- [State list lengths ](#state-list-lengths )
- [Rewards and penalties ](#rewards-and-penalties )
- [Max operations per block ](#max-operations-per-block )
- [Domain types ](#domain-types )
- [Containers ](#containers )
- [Misc dependencies ](#misc-dependencies )
- [`Fork` ](#fork )
2020-03-10 20:41:33 +00:00
- [`ForkData` ](#forkdata )
2019-12-10 14:17:06 +00:00
- [`Checkpoint` ](#checkpoint )
- [`Validator` ](#validator )
- [`AttestationData` ](#attestationdata )
- [`IndexedAttestation` ](#indexedattestation )
- [`PendingAttestation` ](#pendingattestation )
- [`Eth1Data` ](#eth1data )
- [`HistoricalBatch` ](#historicalbatch )
- [`DepositMessage` ](#depositmessage )
- [`DepositData` ](#depositdata )
- [`BeaconBlockHeader` ](#beaconblockheader )
2020-04-21 16:56:27 +00:00
- [`SigningData` ](#signingdata )
2019-12-10 14:17:06 +00:00
- [Beacon operations ](#beacon-operations )
- [`ProposerSlashing` ](#proposerslashing )
- [`AttesterSlashing` ](#attesterslashing )
- [`Attestation` ](#attestation )
- [`Deposit` ](#deposit )
- [`VoluntaryExit` ](#voluntaryexit )
- [Beacon blocks ](#beacon-blocks )
- [`BeaconBlockBody` ](#beaconblockbody )
- [`BeaconBlock` ](#beaconblock )
- [Beacon state ](#beacon-state )
- [`BeaconState` ](#beaconstate )
- [Signed envelopes ](#signed-envelopes )
- [`SignedVoluntaryExit` ](#signedvoluntaryexit )
- [`SignedBeaconBlock` ](#signedbeaconblock )
- [`SignedBeaconBlockHeader` ](#signedbeaconblockheader )
- [Helper functions ](#helper-functions )
- [Math ](#math )
- [`integer_squareroot` ](#integer_squareroot )
- [`xor` ](#xor )
2020-06-25 09:52:05 +00:00
- [`uint_to_bytes` ](#uint_to_bytes )
- [`bytes_to_uint64` ](#bytes_to_uint64 )
2019-12-10 14:17:06 +00:00
- [Crypto ](#crypto )
- [`hash` ](#hash )
- [`hash_tree_root` ](#hash_tree_root )
2019-12-17 13:40:26 +00:00
- [BLS Signatures ](#bls-signatures )
2019-12-10 14:17:06 +00:00
- [Predicates ](#predicates )
- [`is_active_validator` ](#is_active_validator )
2019-12-12 16:48:53 +00:00
- [`is_eligible_for_activation_queue` ](#is_eligible_for_activation_queue )
- [`is_eligible_for_activation` ](#is_eligible_for_activation )
2019-12-10 14:17:06 +00:00
- [`is_slashable_validator` ](#is_slashable_validator )
- [`is_slashable_attestation_data` ](#is_slashable_attestation_data )
- [`is_valid_indexed_attestation` ](#is_valid_indexed_attestation )
- [`is_valid_merkle_branch` ](#is_valid_merkle_branch )
- [Misc ](#misc-1 )
- [`compute_shuffled_index` ](#compute_shuffled_index )
- [`compute_proposer_index` ](#compute_proposer_index )
- [`compute_committee` ](#compute_committee )
- [`compute_epoch_at_slot` ](#compute_epoch_at_slot )
- [`compute_start_slot_at_epoch` ](#compute_start_slot_at_epoch )
- [`compute_activation_exit_epoch` ](#compute_activation_exit_epoch )
2020-03-10 20:41:33 +00:00
- [`compute_fork_data_root` ](#compute_fork_data_root )
2020-03-11 17:51:31 +00:00
- [`compute_fork_digest` ](#compute_fork_digest )
2019-12-10 14:17:06 +00:00
- [`compute_domain` ](#compute_domain )
2020-01-13 09:32:34 +00:00
- [`compute_signing_root` ](#compute_signing_root )
2019-12-10 14:17:06 +00:00
- [Beacon state accessors ](#beacon-state-accessors )
- [`get_current_epoch` ](#get_current_epoch )
- [`get_previous_epoch` ](#get_previous_epoch )
- [`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 )
- [`get_validator_churn_limit` ](#get_validator_churn_limit )
- [`get_seed` ](#get_seed )
2020-06-17 18:04:40 +00:00
- [`get_committee_count_per_slot` ](#get_committee_count_per_slot )
2019-12-10 14:17:06 +00:00
- [`get_beacon_committee` ](#get_beacon_committee )
- [`get_beacon_proposer_index` ](#get_beacon_proposer_index )
- [`get_total_balance` ](#get_total_balance )
- [`get_total_active_balance` ](#get_total_active_balance )
- [`get_domain` ](#get_domain )
- [`get_indexed_attestation` ](#get_indexed_attestation )
- [`get_attesting_indices` ](#get_attesting_indices )
- [Beacon state mutators ](#beacon-state-mutators )
- [`increase_balance` ](#increase_balance )
- [`decrease_balance` ](#decrease_balance )
- [`initiate_validator_exit` ](#initiate_validator_exit )
- [`slash_validator` ](#slash_validator )
- [Genesis ](#genesis )
- [Genesis state ](#genesis-state )
- [Genesis block ](#genesis-block )
- [Beacon chain state transition function ](#beacon-chain-state-transition-function )
- [Epoch processing ](#epoch-processing )
- [Helper functions ](#helper-functions-1 )
- [Justification and finalization ](#justification-and-finalization )
- [Rewards and penalties ](#rewards-and-penalties-1 )
2020-04-29 15:56:48 +00:00
- [Helpers ](#helpers )
- [Components of attestation deltas ](#components-of-attestation-deltas )
- [`get_attestation_deltas` ](#get_attestation_deltas )
- [`process_rewards_and_penalties` ](#process_rewards_and_penalties )
2019-12-10 14:17:06 +00:00
- [Registry updates ](#registry-updates )
- [Slashings ](#slashings )
- [Final updates ](#final-updates )
- [Block processing ](#block-processing )
- [Block header ](#block-header )
- [RANDAO ](#randao )
- [Eth1 data ](#eth1-data )
- [Operations ](#operations )
- [Proposer slashings ](#proposer-slashings )
- [Attester slashings ](#attester-slashings )
- [Attestations ](#attestations )
- [Deposits ](#deposits )
- [Voluntary exits ](#voluntary-exits )
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
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
2018-11-14 21:01:57 +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.
2019-10-17 01:47:39 +00:00
The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block (Phase 1) and proof-of-stake votes for a beacon block (Phase 0).
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
2019-06-15 20:57:50 +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 |
2019-10-17 08:47:51 +00:00
| `CommitteeIndex` | `uint64` | a committee index at a slot |
2019-06-15 20:57:50 +00:00
| `ValidatorIndex` | `uint64` | a validator registry index |
| `Gwei` | `uint64` | an amount in Gwei |
2019-11-12 20:29:58 +00:00
| `Root` | `Bytes32` | a Merkle root |
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 |
2020-03-10 17:59:34 +00:00
| `ForkDigest` | `Bytes4` | a digest of the current fork data |
2020-03-05 16:21:32 +00:00
| `Domain` | `Bytes32` | a signature domain |
2019-06-15 20:57:50 +00:00
| `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 |
| - | - |
2020-01-05 22:03:13 +00:00
| `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` |
2019-06-18 14:24:23 +00:00
| `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` |
2020-04-23 15:46:27 +00:00
| `BASE_REWARDS_PER_EPOCH` | `uint64(4)` |
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `uint64(2**5)` (= 32) |
| `JUSTIFICATION_BITS_LENGTH` | `uint64(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
2018-12-04 10:57:09 +00:00
### Misc
2019-02-12 13:37:30 +00:00
| Name | Value |
2019-02-16 09:11:29 +00:00
| - | - |
2020-06-18 00:47:11 +00:00
| `ETH1_FOLLOW_DISTANCE` | `uint64(2**10)` (= 1,024) |
2020-04-23 15:46:27 +00:00
| `MAX_COMMITTEES_PER_SLOT` | `uint64(2**6)` (= 64) |
| `TARGET_COMMITTEE_SIZE` | `uint64(2**7)` (= 128) |
| `MAX_VALIDATORS_PER_COMMITTEE` | `uint64(2**11)` (= 2,048) |
| `MIN_PER_EPOCH_CHURN_LIMIT` | `uint64(2**2)` (= 4) |
| `CHURN_LIMIT_QUOTIENT` | `uint64(2**16)` (= 65,536) |
| `SHUFFLE_ROUND_COUNT` | `uint64(90)` |
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `uint64(2**14)` (= 16,384) |
| `MIN_GENESIS_TIME` | `uint64(1578009600)` (Jan 3, 2020) |
| `HYSTERESIS_QUOTIENT` | `uint64(4)` |
| `HYSTERESIS_DOWNWARD_MULTIPLIER` | `uint64(1)` |
| `HYSTERESIS_UPWARD_MULTIPLIER` | `uint64(5)` |
2020-03-03 17:58:47 +00:00
2019-12-12 02:17:20 +00:00
- For the safety of committees, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111 ](http://web.archive.org/web/20190504131341/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.)
2018-12-04 10:57:09 +00:00
2019-02-06 16:34:19 +00:00
### Gwei values
2019-06-15 20:57:50 +00:00
| Name | Value |
2019-06-21 20:30:22 +00:00
| - | - |
2019-06-15 20:57:50 +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) |
2018-12-04 10:57:09 +00:00
### Initial values
| Name | Value |
| - | - |
2020-01-04 00:48:03 +00:00
| `GENESIS_FORK_VERSION` | `Version('0x00000000')` |
2019-12-27 08:37:26 +00:00
| `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` |
2018-12-04 10:57:09 +00:00
### Time parameters
2018-11-30 14:28:33 +00:00
2019-07-01 03:13:41 +00:00
| Name | Value | Unit | Duration |
2018-11-30 14:28:33 +00:00
| - | - | :-: | :-: |
2020-06-18 05:45:32 +00:00
| `GENESIS_DELAY` | `uint64(172800)` | seconds | 2 days |
2020-04-23 15:46:27 +00:00
| `SECONDS_PER_SLOT` | `uint64(12)` | seconds | 12 seconds |
2020-06-18 05:45:32 +00:00
| `SECONDS_PER_ETH1_BLOCK` | `uint64(14)` | seconds | 14 seconds |
2020-04-23 15:46:27 +00:00
| `MIN_ATTESTATION_INCLUSION_DELAY` | `uint64(2**0)` (= 1) | slots | 12 seconds |
| `SLOTS_PER_EPOCH` | `uint64(2**5)` (= 32) | slots | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `uint64(2**0)` (= 1) | epochs | 6.4 minutes |
| `MAX_SEED_LOOKAHEAD` | `uint64(2**2)` (= 4) | epochs | 25.6 minutes |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `uint64(2**2)` (= 4) | epochs | 25.6 minutes |
| `EPOCHS_PER_ETH1_VOTING_PERIOD` | `uint64(2**5)` (= 32) | epochs | ~3.4 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `uint64(2**13)` (= 8,192) | slots | ~27 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `uint64(2**8)` (= 256) | epochs | ~27 hours |
2020-05-15 13:53:14 +00:00
| `SHARD_COMMITTEE_PERIOD` | `uint64(2**8)` (= 256) | epochs | ~27 hours |
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-01-28 05:12:37 +00:00
| - | - | :-: | :-: |
2020-04-23 15:46:27 +00:00
| `EPOCHS_PER_HISTORICAL_VECTOR` | `uint64(2**16)` (= 65,536) | epochs | ~0.8 years |
| `EPOCHS_PER_SLASHINGS_VECTOR` | `uint64(2**13)` (= 8,192) | epochs | ~36 days |
| `HISTORICAL_ROOTS_LIMIT` | `uint64(2**24)` (= 16,777,216) | historical roots | ~52,262 years |
| `VALIDATOR_REGISTRY_LIMIT` | `uint64(2**40)` (= 1,099,511,627,776) | validators |
2018-11-30 14:28:33 +00:00
2019-05-29 20:40:46 +00:00
### Rewards and penalties
2018-10-03 07:27:39 +00:00
2018-11-30 14:28:33 +00:00
| Name | Value |
| - | - |
2020-04-23 15:46:27 +00:00
| `BASE_REWARD_FACTOR` | `uint64(2**6)` (= 64) |
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `uint64(2**9)` (= 512) |
| `PROPOSER_REWARD_QUOTIENT` | `uint64(2**3)` (= 8) |
| `INACTIVITY_PENALTY_QUOTIENT` | `uint64(2**24)` (= 16,777,216) |
| `MIN_SLASHING_PENALTY_QUOTIENT` | `uint64(2**5)` (= 32) |
2018-10-03 07:27:39 +00:00
2020-04-08 02:32:16 +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)` .
2018-12-04 10:57:09 +00:00
2019-03-31 05:02:10 +00:00
### 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) |
2020-05-07 20:38:32 +00:00
| `MAX_ATTESTER_SLASHINGS` | `2**1` (= 2) |
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) |
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
2018-12-10 19:55:11 +00:00
| Name | Value |
2018-11-30 14:28:33 +00:00
| - | - |
2020-02-11 22:45:51 +00:00
| `DOMAIN_BEACON_PROPOSER` | `DomainType('0x00000000')` |
| `DOMAIN_BEACON_ATTESTER` | `DomainType('0x01000000')` |
| `DOMAIN_RANDAO` | `DomainType('0x02000000')` |
| `DOMAIN_DEPOSIT` | `DomainType('0x03000000')` |
| `DOMAIN_VOLUNTARY_EXIT` | `DomainType('0x04000000')` |
| `DOMAIN_SELECTION_PROOF` | `DomainType('0x05000000')` |
| `DOMAIN_AGGREGATE_AND_PROOF` | `DomainType('0x06000000')` |
2019-06-09 19:41:21 +00:00
## Containers
2020-01-10 18:42:55 +00:00
The following types are [SimpleSerialize (SSZ) ](../../ssz/simple-serialize.md ) containers.
2019-06-09 19:41:21 +00:00
*Note*: The definitions are ordered topologically to facilitate execution of the spec.
2018-11-30 14:28:33 +00:00
2019-06-22 15:38:30 +00:00
*Note*: Fields missing in container instantiations default to their zero value.
2019-03-07 18:02:13 +00:00
### Misc dependencies
2018-11-30 14:28:33 +00:00
2019-03-07 18:02:13 +00:00
#### `Fork`
2018-11-30 14:28:33 +00:00
```python
2019-05-27 18:29:53 +00:00
class Fork(Container):
2019-06-15 21:32:52 +00:00
previous_version: Version
current_version: Version
2019-06-15 14:51:17 +00:00
epoch: Epoch # Epoch of latest fork
2018-11-30 14:28:33 +00:00
```
2020-03-10 20:41:33 +00:00
#### `ForkData`
```python
class ForkData(Container):
current_version: Version
2020-03-11 17:51:31 +00:00
genesis_validators_root: Root
2020-03-10 20:41:33 +00:00
```
2019-06-21 22:33:43 +00:00
#### `Checkpoint`
```python
class Checkpoint(Container):
epoch: Epoch
2019-11-12 20:29:58 +00:00
root: Root
2019-06-21 22:33:43 +00:00
```
2019-06-05 05:57:54 +00:00
#### `Validator`
2018-12-06 23:51:01 +00:00
```python
2019-06-05 05:57:54 +00:00
class Validator(Container):
2019-06-15 21:23:44 +00:00
pubkey: BLSPubkey
2019-11-12 20:29:58 +00:00
withdrawal_credentials: Bytes32 # Commitment to pubkey for withdrawals
2019-06-15 14:51:17 +00:00
effective_balance: Gwei # Balance at stake
2019-06-27 08:51:06 +00:00
slashed: boolean
2019-06-09 19:41:21 +00:00
# Status epochs
2019-06-15 14:51:17 +00:00
activation_eligibility_epoch: Epoch # When criteria for activation were met
2019-06-11 04:15:52 +00:00
activation_epoch: Epoch
exit_epoch: Epoch
2019-10-24 12:49:07 +00:00
withdrawable_epoch: Epoch # When validator can withdraw funds
2018-12-06 23:51:01 +00:00
```
2019-03-07 18:02:13 +00:00
#### `AttestationData`
2018-11-20 07:40:04 +00:00
2018-10-02 02:21:15 +00:00
```python
2019-05-27 18:29:53 +00:00
class AttestationData(Container):
2019-10-12 02:48:34 +00:00
slot: Slot
2019-10-17 08:47:51 +00:00
index: CommitteeIndex
2019-03-12 10:17:34 +00:00
# LMD GHOST vote
2019-11-12 20:29:58 +00:00
beacon_block_root: Root
2019-03-12 10:17:34 +00:00
# FFG vote
2019-06-22 20:49:53 +00:00
source: Checkpoint
target: Checkpoint
2018-10-02 02:21:15 +00:00
```
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
2019-05-27 18:29:53 +00:00
class IndexedAttestation(Container):
2019-11-02 03:02:53 +00:00
attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]
2019-05-12 21:56:53 +00:00
data: AttestationData
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2019-03-07 18:02:13 +00:00
```
#### `PendingAttestation`
```python
2019-05-27 18:29:53 +00:00
class PendingAttestation(Container):
2019-06-29 17:21:13 +00:00
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
2019-05-12 21:56:53 +00:00
data: AttestationData
2019-06-09 19:41:21 +00:00
inclusion_delay: Slot
2019-06-11 04:15:52 +00:00
proposer_index: ValidatorIndex
2019-03-07 18:02:13 +00:00
```
2019-06-05 05:57:54 +00:00
#### `Eth1Data`
```python
class Eth1Data(Container):
2019-11-12 20:29:58 +00:00
deposit_root: Root
2019-06-05 05:57:54 +00:00
deposit_count: uint64
2019-11-12 20:29:58 +00:00
block_hash: Bytes32
2019-06-05 05:57:54 +00:00
```
2019-03-08 17:13:05 +00:00
#### `HistoricalBatch`
```python
2019-05-27 18:29:53 +00:00
class HistoricalBatch(Container):
2019-11-12 20:29:58 +00:00
block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
2019-03-08 17:13:05 +00:00
```
2019-11-21 22:13:45 +00:00
#### `DepositMessage`
```python
class DepositMessage(Container):
pubkey: BLSPubkey
withdrawal_credentials: Bytes32
amount: Gwei
```
2019-03-15 11:18:06 +00:00
#### `DepositData`
2018-11-20 07:40:04 +00:00
```python
2019-05-27 18:29:53 +00:00
class DepositData(Container):
2019-06-15 21:23:44 +00:00
pubkey: BLSPubkey
2019-11-12 20:29:58 +00:00
withdrawal_credentials: Bytes32
2019-06-11 04:15:52 +00:00
amount: Gwei
2019-12-15 11:10:43 +00:00
signature: BLSSignature # Signing over DepositMessage
2018-12-13 15:36:57 +00:00
```
2019-03-07 18:02:13 +00:00
#### `BeaconBlockHeader`
2018-12-07 01:13:19 +00:00
```python
2019-05-27 18:29:53 +00:00
class BeaconBlockHeader(Container):
2019-06-11 04:15:52 +00:00
slot: Slot
2020-02-17 19:02:24 +00:00
proposer_index: ValidatorIndex
2019-11-12 20:29:58 +00:00
parent_root: Root
state_root: Root
body_root: Root
2019-11-21 22:13:45 +00:00
```
2020-04-21 16:56:27 +00:00
#### `SigningData`
2019-12-17 10:04:56 +00:00
```python
2020-04-21 16:56:27 +00:00
class SigningData(Container):
2020-01-03 06:46:27 +00:00
object_root: Root
2019-12-17 10:04:56 +00:00
domain: Domain
```
2019-03-31 05:02:10 +00:00
### Beacon operations
2019-03-07 18:02:13 +00:00
#### `ProposerSlashing`
```python
2019-05-27 18:29:53 +00:00
class ProposerSlashing(Container):
2019-11-21 22:13:45 +00:00
signed_header_1: SignedBeaconBlockHeader
signed_header_2: SignedBeaconBlockHeader
2019-03-07 18:02:13 +00:00
```
#### `AttesterSlashing`
```python
2019-05-27 18:29:53 +00:00
class AttesterSlashing(Container):
2019-05-12 21:56:53 +00:00
attestation_1: IndexedAttestation
attestation_2: IndexedAttestation
2019-03-07 18:02:13 +00:00
```
#### `Attestation`
```python
2019-05-27 18:29:53 +00:00
class Attestation(Container):
2019-06-29 17:21:13 +00:00
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
2019-05-12 21:56:53 +00:00
data: AttestationData
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2018-12-07 01:13:19 +00:00
```
2019-03-07 18:02:13 +00:00
#### `Deposit`
2018-12-07 01:13:19 +00:00
2019-03-07 18:02:13 +00:00
```python
2019-05-27 18:29:53 +00:00
class Deposit(Container):
2019-12-15 11:10:43 +00:00
proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit root
2019-05-12 21:56:53 +00:00
data: DepositData
2019-03-07 18:02:13 +00:00
```
#### `VoluntaryExit`
2018-12-07 01:02:23 +00:00
```python
2019-05-27 18:29:53 +00:00
class VoluntaryExit(Container):
2019-06-15 14:51:17 +00:00
epoch: Epoch # Earliest epoch when voluntary exit can be processed
2019-06-11 04:15:52 +00:00
validator_index: ValidatorIndex
2019-11-21 22:13:45 +00:00
```
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`
2018-11-20 07:40:04 +00:00
```python
2019-05-27 18:29:53 +00:00
class BeaconBlockBody(Container):
2019-06-15 21:23:44 +00:00
randao_reveal: BLSSignature
2019-06-15 14:51:17 +00:00
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]
2019-11-21 22:13:45 +00:00
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
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
2019-05-27 18:29:53 +00:00
class BeaconBlock(Container):
2019-06-11 04:15:52 +00:00
slot: Slot
2020-02-17 19:02:24 +00:00
proposer_index: ValidatorIndex
2019-11-12 20:29:58 +00:00
parent_root: Root
state_root: Root
2019-05-12 21:56:53 +00:00
body: BeaconBlockBody
2019-11-21 22:13:45 +00:00
```
2019-03-07 18:02:13 +00:00
### Beacon state
2018-09-20 05:20:49 +00:00
2018-11-30 14:28:33 +00:00
#### `BeaconState`
2018-09-20 05:20:49 +00:00
```python
2019-05-27 18:29:53 +00:00
class BeaconState(Container):
2019-06-09 19:41:21 +00:00
# Versioning
2019-05-12 21:56:53 +00:00
genesis_time: uint64
2020-03-05 16:21:32 +00:00
genesis_validators_root: Root
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-11-12 20:29:58 +00:00
block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT]
2019-06-09 19:41:21 +00:00
# Eth1
eth1_data: Eth1Data
2020-02-18 13:12:43 +00:00
eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]
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-10-17 08:47:51 +00:00
# Randomness
2019-11-12 20:29:58 +00:00
randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR]
2019-06-09 19:41:21 +00:00
# Slashings
2019-06-28 13:35:26 +00:00
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
2019-06-09 19:41:21 +00:00
# Attestations
2019-06-20 18:38:42 +00:00
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
2019-06-21 22:33:43 +00:00
previous_justified_checkpoint: Checkpoint # Previous epoch snapshot
current_justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
2018-09-20 05:20:49 +00:00
```
2019-12-03 20:34:48 +00:00
### Signed envelopes
#### `SignedVoluntaryExit`
```python
class SignedVoluntaryExit(Container):
message: VoluntaryExit
signature: BLSSignature
```
#### `SignedBeaconBlock`
```python
class SignedBeaconBlock(Container):
message: BeaconBlock
signature: BLSSignature
```
#### `SignedBeaconBlockHeader`
```python
class SignedBeaconBlockHeader(Container):
message: BeaconBlockHeader
signature: BLSSignature
```
2019-01-28 19:15:43 +00:00
## Helper functions
2018-12-04 11:47:41 +00:00
2019-05-06 15:30:32 +00:00
*Note*: The definitions below are for specification purposes and are not necessarily optimal implementations.
2018-12-04 11:47:41 +00:00
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
```
2020-06-25 09:52:05 +00:00
#### `uint_to_bytes`
2019-07-10 17:11:34 +00:00
2020-06-29 04:33:52 +00:00
`def uint_to_bytes(n: uint) -> bytes` is a function for serializing the `uint` type object to bytes in ``ENDIANNESS``-endian. The expected length of the output is the byte-length of the `uint` type.
2019-06-30 09:56:14 +00:00
2020-06-25 09:52:05 +00:00
#### `bytes_to_uint64`
2019-06-30 09:56:14 +00:00
```python
2020-06-25 09:52:05 +00:00
def bytes_to_uint64(data: bytes) -> uint64:
2019-06-30 09:56:14 +00:00
"""
2019-12-16 11:55:18 +00:00
Return the integer deserialization of ``data`` interpreted as ``ENDIANNESS``-endian.
2019-06-30 09:56:14 +00:00
"""
2020-04-23 15:46:27 +00:00
return uint64(int.from_bytes(data, ENDIANNESS))
2019-06-30 09:56:14 +00:00
```
2019-06-30 09:02:18 +00:00
### Crypto
#### `hash`
2018-12-04 11:47:41 +00:00
2019-11-12 20:29:58 +00:00
`def hash(data: bytes) -> Bytes32` is SHA256.
2018-12-04 11:47:41 +00:00
2019-06-30 09:02:18 +00:00
#### `hash_tree_root`
2020-01-10 18:42:55 +00:00
`def hash_tree_root(object: SSZSerializable) -> Root` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the [SSZ spec ](../../ssz/simple-serialize.md#merkleization ).
2018-12-04 11:47:41 +00:00
2019-12-17 10:04:56 +00:00
#### BLS Signatures
2019-02-15 00:23:03 +00:00
2020-05-14 16:48:53 +00:00
Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification draft-irtf-cfrg-bls-signature-02 ](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-02 ) but uses [Hashing to Elliptic Curves - draft-irtf-cfrg-hash-to-curve-07 ](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-07 ) instead of draft-irtf-cfrg-hash-to-curve-06. Specifically, eth2 uses the `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_` ciphersuite which implements the following interfaces:
2019-02-15 00:23:03 +00:00
2020-01-03 06:46:27 +00:00
- `def Sign(SK: int, message: Bytes) -> BLSSignature`
- `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool`
- `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature`
2020-01-13 04:49:03 +00:00
- `def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool`
2020-05-13 04:56:50 +00:00
- `def AggregateVerify(PKs: Sequence[BLSPubkey], messages: Sequence[Bytes], signature: BLSSignature) -> bool`
2019-05-21 17:30:38 +00:00
2019-12-20 06:41:46 +00:00
Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used.
2019-06-30 09:02:18 +00:00
2020-05-13 05:01:08 +00:00
*Note*: The non-standard configuration of the BLS and hash to curve specs is temporary and will be resolved once IETF releases BLS spec draft 3.
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
```
2019-12-11 23:10:18 +00:00
#### `is_eligible_for_activation_queue`
```python
def is_eligible_for_activation_queue(validator: Validator) -> bool:
"""
Check if ``validator`` is eligible to be placed into the activation queue.
"""
return (
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
and validator.effective_balance == MAX_EFFECTIVE_BALANCE
)
```
2019-12-11 23:00:46 +00:00
#### `is_eligible_for_activation`
```python
def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool:
"""
Check if ``validator`` is eligible for activation.
"""
return (
2019-12-12 13:53:56 +00:00
# Placement in queue is finalized
validator.activation_eligibility_epoch < = state.finalized_checkpoint.epoch
2019-12-11 23:00:46 +00:00
# Has not yet been activated
and validator.activation_epoch == FAR_FUTURE_EPOCH
)
```
2019-06-30 09:11:23 +00:00
#### `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 )
)
```
2019-06-30 22:10:28 +00:00
#### `is_valid_indexed_attestation`
```python
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
2020-05-01 13:17:41 +00:00
Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature.
2019-06-30 22:10:28 +00:00
"""
2019-12-12 00:45:59 +00:00
# Verify indices are sorted and unique
2020-04-21 07:50:42 +00:00
indices = indexed_attestation.attesting_indices
2020-05-01 13:17:41 +00:00
if len(indices) == 0 or not indices == sorted(set(indices)):
2019-06-30 22:10:28 +00:00
return False
# Verify aggregate signature
2019-12-17 10:04:56 +00:00
pubkeys = [state.validators[i].pubkey for i in indices]
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
2020-01-03 07:18:34 +00:00
signing_root = compute_signing_root(indexed_attestation.data, domain)
return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature)
2019-06-30 22:10:28 +00:00
```
2019-06-30 09:56:14 +00:00
#### `is_valid_merkle_branch`
```python
2019-11-12 20:29:58 +00:00
def is_valid_merkle_branch(leaf: Bytes32, branch: Sequence[Bytes32], depth: uint64, index: uint64, root: Root) -> 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
2020-04-09 09:33:14 +00:00
def compute_shuffled_index(index: uint64, index_count: uint64, seed: Bytes32) -> uint64:
2019-06-30 09:56:14 +00:00
"""
2020-04-09 09:33:14 +00:00
Return the shuffled index corresponding to ``seed`` (and ``index_count``).
2019-06-30 09:56:14 +00:00
"""
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
2020-06-29 04:50:01 +00:00
for current_round in range(SHUFFLE_ROUND_COUNT):
pivot = bytes_to_uint64(hash(seed + uint_to_bytes(uint8(current_round)))[0:8]) % index_count
flip = (pivot + index_count - index) % index_count
2019-06-30 09:56:14 +00:00
position = max(index, flip)
2020-06-25 09:52:05 +00:00
source = hash(
seed
2020-06-29 04:50:01 +00:00
+ uint_to_bytes(uint8(current_round))
2020-06-25 09:52:05 +00:00
+ uint_to_bytes(uint32(position // 256))
)
2020-06-26 14:13:38 +00:00
byte = uint8(source[(position % 256) // 8])
2019-06-30 09:56:14 +00:00
bit = (byte >> (position % 8)) % 2
index = flip if bit else index
2020-04-09 09:33:14 +00:00
return index
2019-06-30 09:56:14 +00:00
```
2019-08-28 09:22:34 +00:00
#### `compute_proposer_index`
```python
2019-11-12 20:29:58 +00:00
def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex:
2019-08-28 09:22:34 +00:00
"""
Return from ``indices`` a random index sampled by effective balance.
"""
assert len(indices) > 0
MAX_RANDOM_BYTE = 2**8 - 1
2020-06-26 13:41:47 +00:00
i = uint64(0)
total = uint64(len(indices))
2019-08-28 09:22:34 +00:00
while True:
2020-06-26 13:41:47 +00:00
candidate_index = indices[compute_shuffled_index(i % total, total, seed)]
2020-06-25 09:52:05 +00:00
random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32]
2019-08-28 09:22:34 +00:00
effective_balance = state.validators[candidate_index].effective_balance
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
2020-04-09 09:33:14 +00:00
return candidate_index
2019-08-28 09:22:34 +00:00
i += 1
```
2019-06-30 09:56:14 +00:00
#### `compute_committee`
```python
def compute_committee(indices: Sequence[ValidatorIndex],
2019-11-12 20:29:58 +00:00
seed: Bytes32,
2019-06-30 18:00:22 +00:00
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
2020-04-23 15:46:27 +00:00
return [indices[compute_shuffled_index(uint64(i), uint64(len(indices)), seed)] for i in range(start, end)]
2019-06-30 09:56:14 +00:00
```
2019-10-17 08:47:51 +00:00
#### `compute_epoch_at_slot`
2019-06-30 09:56:14 +00:00
```python
2019-10-17 08:47:51 +00:00
def compute_epoch_at_slot(slot: Slot) -> Epoch:
2019-06-30 09:56:14 +00:00
"""
2019-10-17 08:47:51 +00:00
Return the epoch number at ``slot``.
2019-06-30 09:56:14 +00:00
"""
return Epoch(slot // SLOTS_PER_EPOCH)
```
2019-10-23 00:37:15 +00:00
#### `compute_start_slot_at_epoch`
2019-06-30 09:56:14 +00:00
```python
2019-10-23 00:37:15 +00:00
def compute_start_slot_at_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)
```
2019-06-30 18:16:56 +00:00
#### `compute_activation_exit_epoch`
2019-06-30 09:56:14 +00:00
```python
2019-06-30 18:16:56 +00:00
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
"""
2019-09-23 18:07:10 +00:00
return Epoch(epoch + 1 + MAX_SEED_LOOKAHEAD)
2019-06-30 09:56:14 +00:00
```
2020-03-10 20:41:33 +00:00
#### `compute_fork_data_root`
```python
def compute_fork_data_root(current_version: Version, genesis_validators_root: Root) -> Root:
"""
2020-03-11 17:51:31 +00:00
Return the 32-byte fork data root for the ``current_version`` and ``genesis_validators_root``.
This is used primarily in signature domains to avoid collisions across forks/chains.
2020-03-10 20:41:33 +00:00
"""
return hash_tree_root(ForkData(
current_version=current_version,
genesis_validators_root=genesis_validators_root,
))
```
2020-03-11 17:51:31 +00:00
#### `compute_fork_digest`
```python
2020-03-11 19:24:30 +00:00
def compute_fork_digest(current_version: Version, genesis_validators_root: Root) -> ForkDigest:
2020-03-11 17:51:31 +00:00
"""
Return the 4-byte fork digest for the ``current_version`` and ``genesis_validators_root``.
This is a digest primarily used for domain separation on the p2p layer.
4-bytes suffices for practical separation of forks/chains.
"""
return ForkDigest(compute_fork_data_root(current_version, genesis_validators_root)[:4])
```
2019-06-30 23:35:09 +00:00
#### `compute_domain`
2019-06-30 09:56:14 +00:00
```python
2020-03-11 17:51:31 +00:00
def compute_domain(domain_type: DomainType, fork_version: Version=None, genesis_validators_root: Root=None) -> 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
"""
2020-01-22 14:24:15 +00:00
if fork_version is None:
fork_version = GENESIS_FORK_VERSION
2020-03-11 17:51:31 +00:00
if genesis_validators_root is None:
genesis_validators_root = Root() # all bytes zero by default
fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root)
2020-03-10 20:41:33 +00:00
return Domain(domain_type + fork_data_root[:28])
2019-06-30 09:56:14 +00:00
```
2020-01-13 09:32:34 +00:00
#### `compute_signing_root`
2019-12-17 10:04:56 +00:00
```python
2020-01-03 06:46:27 +00:00
def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
2020-01-07 12:07:09 +00:00
"""
2020-04-21 16:56:27 +00:00
Return the signing root for the corresponding signing data.
2020-01-07 12:07:09 +00:00
"""
2020-04-21 16:56:27 +00:00
return hash_tree_root(SigningData(
2020-01-03 06:46:27 +00:00
object_root=hash_tree_root(ssz_object),
2019-12-17 10:04:56 +00:00
domain=domain,
2020-04-21 16:56:27 +00:00
))
2019-12-17 10:04:56 +00:00
```
2019-06-30 17:51:13 +00:00
### Beacon state accessors
2019-06-30 09:02:18 +00:00
#### `get_current_epoch`
2018-12-04 10:57:09 +00:00
```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
"""
2019-10-17 08:47:51 +00:00
return compute_epoch_at_slot(state.slot)
2018-12-04 10:57:09 +00:00
```
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
"""
2019-04-11 12:48:27 +00:00
current_epoch = get_current_epoch(state)
2019-06-11 04:15:52 +00:00
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-11-12 20:29:58 +00:00
def get_block_root(state: BeaconState, epoch: Epoch) -> Root:
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
"""
2019-10-23 00:37:15 +00:00
return get_block_root_at_slot(state, compute_start_slot_at_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-11-12 20:29:58 +00:00
def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Root:
2018-12-07 12:18:55 +00:00
"""
2019-06-30 09:02:18 +00:00
Return the block root at a recent ``slot``.
2018-12-07 12:18:55 +00:00
"""
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]
2018-12-07 12:18:55 +00:00
```
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-11-12 20:29:58 +00:00
def get_randao_mix(state: BeaconState, epoch: Epoch) -> Bytes32:
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]:
2018-11-30 14:28:33 +00:00
"""
2019-06-30 09:02:18 +00:00
Return the sequence of active validator indices at ``epoch``.
2018-11-30 14:28:33 +00:00
"""
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
```
2018-11-04 22:26:24 +00:00
2019-06-30 13:11:46 +00:00
#### `get_validator_churn_limit`
2019-03-07 07:38:03 +00:00
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))
2020-06-26 13:41:47 +00:00
return max(MIN_PER_EPOCH_CHURN_LIMIT, uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT)
2019-03-21 16:04:20 +00:00
```
2019-03-07 07:38:03 +00:00
2019-06-30 13:11:46 +00:00
#### `get_seed`
```python
2019-11-12 20:29:58 +00:00
def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Bytes32:
2019-06-30 13:11:46 +00:00
"""
Return the seed at ``epoch``.
"""
2019-07-14 22:05:51 +00:00
mix = get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1)) # Avoid underflow
2020-06-25 09:52:05 +00:00
return hash(domain_type + uint_to_bytes(epoch) + mix)
2019-06-30 13:11:46 +00:00
```
2019-03-07 07:38:03 +00:00
2020-06-17 18:04:40 +00:00
#### `get_committee_count_per_slot`
2019-01-08 00:53:33 +00:00
```python
2020-06-17 18:04:40 +00:00
def get_committee_count_per_slot(state: BeaconState, epoch: Epoch) -> uint64:
2019-01-30 09:25:39 +00:00
"""
2020-06-17 18:23:26 +00:00
Return the number of committees in each slot for the given ``epoch``.
2019-01-30 09:25:39 +00:00
"""
2020-04-23 15:46:27 +00:00
return max(uint64(1), min(
2019-10-13 04:53:43 +00:00
MAX_COMMITTEES_PER_SLOT,
2020-06-26 13:41:47 +00:00
uint64(len(get_active_validator_indices(state, epoch))) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE,
2019-06-30 17:42:24 +00:00
))
2019-01-08 00:53:33 +00:00
```
2019-10-17 01:45:07 +00:00
#### `get_beacon_committee`
2018-09-20 05:20:49 +00:00
```python
2019-10-17 01:45:07 +00:00
def get_beacon_committee(state: BeaconState, slot: Slot, index: CommitteeIndex) -> Sequence[ValidatorIndex]:
2019-06-28 17:10:17 +00:00
"""
2019-10-17 01:47:39 +00:00
Return the beacon committee at ``slot`` for ``index``.
2019-06-30 09:02:18 +00:00
"""
2019-10-17 08:47:51 +00:00
epoch = compute_epoch_at_slot(slot)
2020-06-17 18:04:40 +00:00
committees_per_slot = get_committee_count_per_slot(state, epoch)
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-18 03:17:46 +00:00
index=(slot % SLOTS_PER_EPOCH) * committees_per_slot + index,
2019-10-13 12:52:58 +00:00
count=committees_per_slot * SLOTS_PER_EPOCH,
2019-06-30 09:02:18 +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)
2020-06-25 09:52:05 +00:00
seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + uint_to_bytes(state.slot))
2019-08-28 09:22:34 +00:00
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`
2019-01-25 23:07:54 +00:00
```python
2019-06-30 09:02:18 +00:00
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
2019-01-10 17:01:19 +00:00
"""
2020-03-16 17:19:21 +00:00
Return the combined effective balance of the ``indices``.
``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
2020-03-10 19:12:17 +00:00
Math safe up to ~10B ETH, afterwhich this overflows uint64.
2019-01-10 17:01:19 +00:00
"""
2020-03-16 17:19:21 +00:00
return Gwei(max(EFFECTIVE_BALANCE_INCREMENT, 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.
2020-03-18 15:55:09 +00:00
Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
2019-06-30 13:11:46 +00:00
"""
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
2020-01-07 12:07:09 +00:00
def get_domain(state: BeaconState, domain_type: DomainType, 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.
"""
2020-01-07 12:07:09 +00:00
epoch = get_current_epoch(state) if epoch is None else epoch
2019-06-30 09:02:18 +00:00
fork_version = state.fork.previous_version if epoch < state.fork.epoch else state . fork . current_version
2020-03-05 16:21:32 +00:00
return compute_domain(domain_type, fork_version, state.genesis_validators_root)
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)
return IndexedAttestation(
2019-11-02 03:02:53 +00:00
attesting_indices=sorted(attesting_indices),
2019-06-30 09:02:18 +00:00
data=attestation.data,
signature=attestation.signature,
2019-01-25 23:07:54 +00:00
)
2019-01-10 17:01:19 +00:00
```
2019-06-30 09:02:18 +00:00
#### `get_attesting_indices`
2018-11-20 07:40:04 +00:00
```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]:
2018-11-30 14:28:33 +00:00
"""
2019-06-30 09:02:18 +00:00
Return the set of attesting indices corresponding to ``data`` and ``bits``.
2018-11-30 14:28:33 +00:00
"""
2019-10-17 01:45:07 +00:00
committee = get_beacon_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])
2018-11-20 07:40:04 +00:00
```
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
```
2019-01-28 19:15:43 +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
2018-10-11 18:14:48 +00:00
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]
2020-01-21 03:03:38 +00:00
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):
2019-06-11 04:15:52 +00:00
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
2019-06-11 04:15:52 +00:00
validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
2018-10-11 18:14:48 +00:00
```
2019-02-12 12:24:19 +00:00
#### `slash_validator`
2019-01-28 19:15:43 +00:00
2018-12-28 18:04:03 +00:00
```python
2019-05-09 05:54:38 +00:00
def slash_validator(state: BeaconState,
slashed_index: ValidatorIndex,
whistleblower_index: ValidatorIndex=None) -> None:
2019-01-30 09:25:39 +00:00
"""
2019-03-25 14:30:59 +00:00
Slash the validator with index ``slashed_index``.
2019-01-30 09:25:39 +00:00
"""
2019-06-28 13:35:26 +00:00
epoch = get_current_epoch(state)
2019-03-29 07:26:26 +00:00
initiate_validator_exit(state, slashed_index)
2019-06-28 13:35:26 +00:00
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)
2019-03-25 14:30:59 +00:00
2019-06-28 13:35:26 +00:00
# Apply proposer and whistleblower rewards
2019-06-30 17:42:24 +00:00
proposer_index = get_beacon_proposer_index(state)
2019-03-25 14:49:35 +00:00
if whistleblower_index is None:
whistleblower_index = proposer_index
2019-06-28 13:35:26 +00:00
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
2019-03-25 14:30:59 +00:00
increase_balance(state, proposer_index, proposer_reward)
2020-04-17 09:27:57 +00:00
increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
2018-12-28 18:04:03 +00:00
```
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`
2019-10-31 23:51:21 +00:00
- `deposits` is the sequence of all deposits, ordered chronologically, up to (and including) the block with hash `eth1_block_hash`
2019-03-03 11:04:28 +00:00
2020-06-01 11:59:03 +00:00
Eth1 blocks must only be considered once they are at least `SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE` seconds old (i.e. `eth1_timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time` ). Due to this constraint, if `GENESIS_DELAY < SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE` , then the `genesis_time` can happen before the time/state is first known. Values should be configured to avoid this case.
2020-05-20 16:44:08 +00:00
2019-06-08 18:00:50 +00:00
```python
2019-11-12 20:29:58 +00:00
def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
2019-06-29 22:38:30 +00:00
eth1_timestamp: uint64,
deposits: Sequence[Deposit]) -> BeaconState:
2020-01-04 00:48:03 +00:00
fork = Fork(
previous_version=GENESIS_FORK_VERSION,
current_version=GENESIS_FORK_VERSION,
epoch=GENESIS_EPOCH,
)
2019-05-20 09:16:20 +00:00
state = BeaconState(
2020-06-01 11:59:03 +00:00
genesis_time=eth1_timestamp + GENESIS_DELAY,
2020-01-04 00:48:03 +00:00
fork=fork,
2019-06-29 21:06:17 +00:00
eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)),
2019-05-20 09:16:20 +00:00
latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
2019-10-27 18:18:48 +00:00
randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
2019-05-20 09:16:20 +00:00
)
2018-10-09 07:33:22 +00:00
2019-06-29 20:18:18 +00:00
# Process deposits
2019-06-29 19:20:11 +00:00
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:
2019-04-22 05:12:30 +00:00
validator.activation_eligibility_epoch = GENESIS_EPOCH
validator.activation_epoch = GENESIS_EPOCH
2018-12-10 21:16:06 +00:00
2020-03-05 16:21:32 +00:00
# Set genesis validators root for domain separation and chain versioning
state.genesis_validators_root = hash_tree_root(state.validators)
2018-11-15 13:20:25 +00:00
return state
2018-10-02 15:20:07 +00:00
```
2018-09-20 05:20:49 +00:00
2020-04-26 08:09:22 +00:00
*Note*: The ETH1 block with `eth1_timestamp` meeting the minimum genesis active validator count criteria can also occur before `MIN_GENESIS_TIME` .
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.
2019-06-29 22:38:30 +00:00
```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:
2019-06-29 22:38:30 +00:00
return False
2019-06-30 09:56:14 +00:00
return True
2019-06-29 22:38:30 +00:00
```
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))` .
2019-01-28 19:15:43 +00:00
## Beacon chain state transition function
2018-12-28 18:04:03 +00:00
2020-04-21 14:34:55 +00:00
The post-state corresponding to a pre-state `state` and a signed block `signed_block` is defined as `state_transition(state, signed_block)` . State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid. State transitions that cause a `uint64` overflow or underflow are also considered invalid.
2019-02-11 21:30:36 +00:00
2019-05-01 12:14:10 +00:00
```python
2019-11-21 22:13:45 +00:00
def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> BeaconState:
2019-12-15 11:10:43 +00:00
block = signed_block.message
2019-05-08 18:15:23 +00:00
# Process slots (including those with no blocks) since block
2019-12-15 11:10:43 +00:00
process_slots(state, block.slot)
2019-11-21 22:13:45 +00:00
# Verify signature
if validate_result:
assert verify_block_signature(state, signed_block)
2019-05-08 18:15:23 +00:00
# Process block
2019-12-15 11:10:43 +00:00
process_block(state, block)
# Verify state root
2019-11-21 22:13:45 +00:00
if validate_result:
2019-12-15 11:10:43 +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-11-21 22:13:45 +00:00
```python
def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool:
2020-02-17 19:02:24 +00:00
proposer = state.validators[signed_block.message.proposer_index]
2020-01-03 07:18:34 +00:00
signing_root = compute_signing_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER))
return bls.Verify(proposer.pubkey, signing_root, signed_block.signature)
2019-11-21 22:13:45 +00:00
```
2019-05-03 20:21:42 +00:00
```python
def process_slots(state: BeaconState, slot: Slot) -> None:
2020-05-13 14:46:28 +00:00
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)
2020-04-17 09:27:57 +00:00
state.slot = Slot(state.slot + 1)
2019-05-03 20:21:42 +00:00
```
2018-12-12 13:02:50 +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
2019-07-15 00:05:04 +00:00
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-11-21 22:13:45 +00:00
previous_block_root = hash_tree_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
2018-12-10 10:11:41 +00:00
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)
process_slashings(state)
process_final_updates(state)
```
2018-12-10 10:11:41 +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
```
2018-10-11 17:57:30 +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
```
2018-11-30 14:28:33 +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 [
2020-03-11 18:46:47 +00:00
a for a in get_matching_target_attestations(state, epoch)
2019-10-12 02:48:34 +00:00
if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot)
2019-03-07 19:05:34 +00:00
]
```
2018-11-16 12:54:03 +00:00
2019-03-07 19:05:34 +00:00
```python
2019-05-09 05:54:38 +00:00
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]
2019-04-17 04:06:28 +00:00
for a in attestations:
2019-06-28 11:23:22 +00:00
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
2019-07-11 00:00:11 +00:00
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
2019-04-17 04:06:28 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_attesting_balance(state: BeaconState, attestations: Sequence[PendingAttestation]) -> Gwei:
2020-03-18 15:55:09 +00:00
"""
Return the combined effective balance of the set of unslashed validators participating in ``attestations``.
Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
"""
2019-04-22 06:13:46 +00:00
return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
2019-04-17 04:06:28 +00:00
```
2018-11-16 12:54:03 +00:00
2019-04-18 09:08:34 +00:00
#### Justification and finalization
2019-03-07 19:05:34 +00:00
2019-03-01 02:54:59 +00:00
```python
2019-04-18 09:08:34 +00:00
def process_justification_and_finalization(state: BeaconState) -> None:
2020-07-28 10:48:16 +00:00
# Initial FFG checkpoint values have a `0x00` stub for `root` .
2020-07-28 15:48:45 +00:00
# Skip FFG updates in the first two epochs to avoid corner cases that might result in modifying this stub.
2019-04-17 15:38:10 +00:00
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)
2019-06-21 22:33:43 +00:00
old_previous_justified_checkpoint = state.previous_justified_checkpoint
old_current_justified_checkpoint = state.current_justified_checkpoint
2019-03-12 18:32:11 +00:00
2019-04-16 04:59:35 +00:00
# Process justifications
2019-06-21 22:33:43 +00:00
state.previous_justified_checkpoint = state.current_justified_checkpoint
2020-06-26 14:13:38 +00:00
state.justification_bits[1:] = state.justification_bits[:JUSTIFICATION_BITS_LENGTH - 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:
2019-06-28 15:34:31 +00:00
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
2019-04-16 04:59:35 +00:00
# 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:
2019-06-21 22:33:43 +00:00
state.finalized_checkpoint = old_previous_justified_checkpoint
2019-04-16 04:59:35 +00:00
# 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:
2019-06-21 22:33:43 +00:00
state.finalized_checkpoint = old_previous_justified_checkpoint
2019-04-16 04:59:35 +00:00
# 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:
2019-06-21 22:33:43 +00:00
state.finalized_checkpoint = old_current_justified_checkpoint
2019-04-16 04:59:35 +00:00
# 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:
2019-06-21 22:33:43 +00:00
state.finalized_checkpoint = old_current_justified_checkpoint
2019-03-01 02:54:59 +00:00
```
2018-09-20 05:20:49 +00:00
2019-01-28 19:15:43 +00:00
#### Rewards and penalties
2018-12-12 15:07:44 +00:00
2020-04-29 01:26:14 +00:00
##### Helpers
2019-03-01 13:59:52 +00:00
```python
2019-04-22 06:13:46 +00:00
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
2019-05-26 15:42:37 +00:00
total_balance = get_total_active_balance(state)
2019-06-09 19:41:21 +00:00
effective_balance = state.validators[index].effective_balance
2019-06-11 04:15:52 +00:00
return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH)
2019-03-01 13:59:52 +00:00
```
2020-05-19 22:51:46 +00:00
2019-04-17 02:32:50 +00:00
```python
2020-05-19 23:12:53 +00:00
def get_proposer_reward(state: BeaconState, attesting_index: ValidatorIndex) -> Gwei:
return Gwei(get_base_reward(state, attesting_index) // PROPOSER_REWARD_QUOTIENT)
```
2020-05-19 22:51:46 +00:00
```python
def get_finality_delay(state: BeaconState) -> uint64:
return get_previous_epoch(state) - state.finalized_checkpoint.epoch
```
```python
2020-05-20 16:11:47 +00:00
def is_in_inactivity_leak(state: BeaconState) -> bool:
2020-05-19 22:51:46 +00:00
return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
```
2019-04-17 02:32:50 +00:00
```python
2020-04-23 16:26:34 +00:00
def get_eligible_validator_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
2019-04-20 06:10:25 +00:00
previous_epoch = get_previous_epoch(state)
2020-04-23 16:26:34 +00:00
return [
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-03-21 20:11:05 +00:00
]
2020-04-23 16:26:34 +00:00
```
2019-04-24 04:23:51 +00:00
2020-04-23 16:26:34 +00:00
```python
2020-05-05 03:05:10 +00:00
def get_attestation_component_deltas(state: BeaconState,
attestations: Sequence[PendingAttestation]
) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
"""
Helper with shared logic for use by get source, target, and head deltas functions
"""
2020-05-05 21:37:14 +00:00
rewards = [Gwei(0)] * len(state.validators)
penalties = [Gwei(0)] * len(state.validators)
2020-04-23 16:26:34 +00:00
total_balance = get_total_active_balance(state)
unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations)
attesting_balance = get_total_balance(state, unslashed_attesting_indices)
for index in get_eligible_validator_indices(state):
if index in unslashed_attesting_indices:
increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from balance totals to avoid uint64 overflow
2020-05-20 16:11:47 +00:00
if is_in_inactivity_leak(state):
# Since full base reward will be canceled out by inactivity penalty deltas,
# optimal participation receives full base reward compensation here.
2020-05-19 22:51:46 +00:00
rewards[index] += get_base_reward(state, index)
else:
2020-03-03 22:34:02 +00:00
reward_numerator = get_base_reward(state, index) * (attesting_balance // increment)
2020-03-24 06:15:40 +00:00
rewards[index] += reward_numerator // (total_balance // increment)
2020-04-23 16:26:34 +00:00
else:
penalties[index] += get_base_reward(state, index)
return rewards, penalties
```
2019-04-24 04:23:51 +00:00
2020-04-29 01:26:14 +00:00
##### Components of attestation deltas
2020-04-23 16:26:34 +00:00
```python
def get_source_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2020-04-29 01:26:14 +00:00
"""
Return attester micro-rewards/penalties for source-vote for each validator.
"""
2020-04-23 16:26:34 +00:00
matching_source_attestations = get_matching_source_attestations(state, get_previous_epoch(state))
2020-05-05 03:05:10 +00:00
return get_attestation_component_deltas(state, matching_source_attestations)
2020-04-23 16:26:34 +00:00
```
2019-04-24 04:23:51 +00:00
2020-04-23 16:26:34 +00:00
```python
def get_target_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2020-04-29 01:26:14 +00:00
"""
Return attester micro-rewards/penalties for target-vote for each validator.
"""
2020-04-23 17:13:09 +00:00
matching_target_attestations = get_matching_target_attestations(state, get_previous_epoch(state))
2020-05-05 03:05:10 +00:00
return get_attestation_component_deltas(state, matching_target_attestations)
2020-04-23 16:26:34 +00:00
```
2019-04-24 04:23:51 +00:00
2020-04-23 16:26:34 +00:00
```python
def get_head_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2020-04-29 01:26:14 +00:00
"""
Return attester micro-rewards/penalties for head-vote for each validator.
"""
2020-04-29 15:56:48 +00:00
matching_head_attestations = get_matching_head_attestations(state, get_previous_epoch(state))
2020-05-05 03:05:10 +00:00
return get_attestation_component_deltas(state, matching_head_attestations)
2020-04-23 16:26:34 +00:00
```
2019-04-24 04:23:51 +00:00
2020-04-23 16:26:34 +00:00
```python
def get_inclusion_delay_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2020-04-23 17:13:09 +00:00
"""
2020-04-29 01:26:14 +00:00
Return proposer and inclusion delay micro-rewards/penalties for each validator.
2020-04-23 17:13:09 +00:00
"""
2020-04-23 16:26:34 +00:00
rewards = [Gwei(0) for _ in range(len(state.validators))]
matching_source_attestations = get_matching_source_attestations(state, get_previous_epoch(state))
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)
2020-05-19 23:12:53 +00:00
rewards[attestation.proposer_index] += get_proposer_reward(state, index)
max_attester_reward = get_base_reward(state, index) - get_proposer_reward(state, index)
2019-12-15 11:10:43 +00:00
rewards[index] += Gwei(max_attester_reward // attestation.inclusion_delay)
2019-04-24 04:23:51 +00:00
2020-05-08 16:50:05 +00:00
# No penalties associated with inclusion delay
penalties = [Gwei(0) for _ in range(len(state.validators))]
2020-04-23 16:26:34 +00:00
return rewards, penalties
```
2019-04-24 04:23:51 +00:00
2020-04-23 16:26:34 +00:00
```python
def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2020-04-23 17:13:09 +00:00
"""
2020-04-29 01:26:14 +00:00
Return inactivity reward/penalty deltas for each validator.
2020-04-23 17:13:09 +00:00
"""
2020-04-23 16:26:34 +00:00
penalties = [Gwei(0) for _ in range(len(state.validators))]
2020-05-20 16:11:47 +00:00
if is_in_inactivity_leak(state):
2020-04-23 17:13:09 +00:00
matching_target_attestations = get_matching_target_attestations(state, get_previous_epoch(state))
2019-04-24 04:23:51 +00:00
matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations)
2020-04-23 16:26:34 +00:00
for index in get_eligible_validator_indices(state):
2020-05-19 23:12:53 +00:00
# If validator is performing optimally this cancels all rewards for a neutral balance
base_reward = get_base_reward(state, index)
penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * base_reward - get_proposer_reward(state, index))
2019-04-24 04:23:51 +00:00
if index not in matching_target_attesting_indices:
2019-12-15 11:10:43 +00:00
effective_balance = state.validators[index].effective_balance
2020-05-19 22:51:46 +00:00
penalties[index] += Gwei(effective_balance * get_finality_delay(state) // INACTIVITY_PENALTY_QUOTIENT)
2019-04-17 04:06:28 +00:00
2020-05-08 16:50:05 +00:00
# No rewards associated with inactivity penalties
rewards = [Gwei(0) for _ in range(len(state.validators))]
2019-04-25 07:37:05 +00:00
return rewards, penalties
2019-03-01 13:59:52 +00:00
```
2018-09-20 05:20:49 +00:00
2020-04-29 01:26:14 +00:00
##### `get_attestation_deltas`
2020-04-23 16:26:34 +00:00
```python
def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2020-04-29 01:26:14 +00:00
"""
Return attestation reward/penalty deltas for each validator.
"""
2020-04-23 16:26:34 +00:00
source_rewards, source_penalties = get_source_deltas(state)
target_rewards, target_penalties = get_target_deltas(state)
head_rewards, head_penalties = get_head_deltas(state)
inclusion_delay_rewards, _ = get_inclusion_delay_deltas(state)
_, inactivity_penalties = get_inactivity_penalty_deltas(state)
rewards = [
2020-05-05 03:05:10 +00:00
source_rewards[i] + target_rewards[i] + head_rewards[i] + inclusion_delay_rewards[i]
2020-04-23 16:26:34 +00:00
for i in range(len(state.validators))
]
penalties = [
2020-05-05 03:05:10 +00:00
source_penalties[i] + target_penalties[i] + head_penalties[i] + inactivity_penalties[i]
2020-04-23 16:26:34 +00:00
for i in range(len(state.validators))
]
2019-04-17 04:06:28 +00:00
2019-04-25 07:37:05 +00:00
return rewards, penalties
2019-03-01 13:59:52 +00:00
```
2018-09-20 05:20:49 +00:00
2020-04-29 01:26:14 +00:00
##### `process_rewards_and_penalties`
2019-03-01 13:59:52 +00:00
```python
2019-04-18 09:08:34 +00:00
def process_rewards_and_penalties(state: BeaconState) -> None:
2020-07-28 15:48:45 +00:00
# No rewards are applied at the end of `GENESIS_EPOCH` because rewards are for work done in the previous epoch
2019-04-11 12:28:42 +00:00
if get_current_epoch(state) == GENESIS_EPOCH:
return
2019-10-18 03:17:46 +00:00
rewards, penalties = get_attestation_deltas(state)
2019-06-17 21:51:00 +00:00
for index in range(len(state.validators)):
2019-10-18 03:17:46 +00:00
increase_balance(state, ValidatorIndex(index), rewards[index])
decrease_balance(state, ValidatorIndex(index), penalties[index])
2019-03-01 13:59:52 +00:00
```
2018-11-23 04:54:11 +00:00
2019-04-18 09:08:34 +00:00
#### Registry updates
2018-12-13 19:45:08 +00:00
2018-12-05 11:22:15 +00:00
```python
2019-04-18 09:08:34 +00:00
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):
2019-12-11 23:10:18 +00:00
if is_eligible_for_activation_queue(validator):
2019-12-12 13:53:56 +00:00
validator.activation_eligibility_epoch = get_current_epoch(state) + 1
2018-12-04 19:49:26 +00:00
2019-04-20 06:32:41 +00:00
if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance < = EJECTION_BALANCE:
2019-06-11 04:15:52 +00:00
initiate_validator_exit(state, ValidatorIndex(index))
2019-03-07 19:05:34 +00:00
2019-12-10 18:49:26 +00:00
# Queue validators eligible for activation and not yet dequeued for activation
2019-04-06 14:24:50 +00:00
activation_queue = sorted([
2019-06-30 20:59:12 +00:00
index for index, validator in enumerate(state.validators)
2019-12-11 23:00:46 +00:00
if is_eligible_for_activation(state, validator)
2019-12-12 13:53:56 +00:00
# Order by the sequence of activation_eligibility_epoch setting and then index
2019-12-12 13:43:37 +00:00
], key=lambda index: (state.validators[index].activation_eligibility_epoch, index))
2019-12-10 18:25:55 +00:00
# Dequeued validators for activation up to churn limit
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]
2019-12-10 18:25:55 +00:00
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)
2019-05-26 15:42:37 +00:00
total_balance = get_total_active_balance(state)
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
2019-06-28 13:35:26 +00:00
if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
2019-07-11 08:53:51 +00:00
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
2019-06-11 04:15:52 +00:00
decrease_balance(state, ValidatorIndex(index), penalty)
2019-03-07 19:05:34 +00:00
```
#### Final updates
```python
2019-04-18 09:08:34 +00:00
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)
2019-04-17 04:30:03 +00:00
# Reset eth1 data votes
2020-02-18 13:12:43 +00:00
if next_epoch % EPOCHS_PER_ETH1_VOTING_PERIOD == 0:
2019-04-17 04:30:03 +00:00
state.eth1_data_votes = []
2019-04-22 06:13:46 +00:00
# Update effective balances with hysteresis
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
2019-04-26 14:46:35 +00:00
balance = state.balances[index]
2020-03-03 17:58:47 +00:00
HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT
DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
2020-02-18 18:36:20 +00:00
if (
2020-03-03 17:58:47 +00:00
balance + DOWNWARD_THRESHOLD < validator.effective_balance
or validator.effective_balance + UPWARD_THRESHOLD < balance
2020-02-18 18:36:20 +00:00
):
2019-04-26 14:46:35 +00:00
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
2019-06-28 13:35:26 +00:00
# Reset slashings
state.slashings[next_epoch % EPOCHS_PER_SLASHINGS_VECTOR] = Gwei(0)
2019-03-07 19:05:34 +00:00
# Set randao mix
2019-06-19 19:59:44 +00:00
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-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
2020-05-15 22:39:26 +00:00
# Verify that the block is newer than latest block header
assert block.slot > state.latest_block_header.slot
2020-02-17 19:02:24 +00:00
# Verify that proposer index is the correct index
assert block.proposer_index == get_beacon_proposer_index(state)
2019-03-07 19:05:34 +00:00
# Verify that the parent matches
2019-11-21 22:13:45 +00:00
assert block.parent_root == hash_tree_root(state.latest_block_header)
2019-12-15 11:10:43 +00:00
# Cache current block as the new latest block
2019-04-19 08:26:54 +00:00
state.latest_block_header = BeaconBlockHeader(
slot=block.slot,
2020-02-17 19:02:24 +00:00
proposer_index=block.proposer_index,
2019-05-06 19:49:46 +00:00
parent_root=block.parent_root,
2019-12-15 11:10:43 +00:00
state_root=Bytes32(), # Overwritten in the next process_slot call
2019-05-07 07:52:56 +00:00
body_root=hash_tree_root(block.body),
2019-04-19 08:26:54 +00:00
)
2019-12-15 11:10:43 +00:00
2019-03-17 11:48:47 +00:00
# Verify proposer is not slashed
2020-02-17 19:02:24 +00:00
proposer = state.validators[block.proposer_index]
2019-03-11 22:07:34 +00:00
assert not proposer.slashed
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:
2019-06-19 19:59:44 +00:00
epoch = get_current_epoch(state)
# Verify RANDAO reveal
2019-06-30 17:42:24 +00:00
proposer = state.validators[get_beacon_proposer_index(state)]
2020-01-03 07:18:34 +00:00
signing_root = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO))
assert bls.Verify(proposer.pubkey, signing_root, body.randao_reveal)
2019-06-19 19:59:44 +00:00
# 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)
2020-02-18 13:12:43 +00:00
if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
2019-06-09 19:41:21 +00:00
state.eth1_data = body.eth1_data
2019-03-07 19:05:34 +00:00
```
2019-03-31 05:02:10 +00:00
#### Operations
2019-03-07 19:05:34 +00:00
2019-05-01 11:04:27 +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-06-18 00:54:08 +00:00
2019-11-20 03:43:32 +00:00
def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
2019-05-01 11:04:27 +00:00
for operation in operations:
2019-11-16 10:13:47 +00:00
fn(state, operation)
for_ops(body.proposer_slashings, process_proposer_slashing)
for_ops(body.attester_slashings, process_attester_slashing)
2019-11-18 20:47:53 +00:00
for_ops(body.attestations, process_attestation)
2019-11-16 10:13:47 +00:00
for_ops(body.deposits, process_deposit)
for_ops(body.voluntary_exits, process_voluntary_exit)
2019-05-01 11:04:27 +00:00
```
2019-03-07 19:05:34 +00:00
2019-05-01 11:04:27 +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:
2020-02-17 19:02:24 +00:00
header_1 = proposer_slashing.signed_header_1.message
header_2 = proposer_slashing.signed_header_2.message
2019-12-15 11:10:43 +00:00
# Verify header slots match
2020-02-17 19:02:24 +00:00
assert header_1.slot == header_2.slot
# Verify header proposer indices match
assert header_1.proposer_index == header_2.proposer_index
2019-12-15 11:10:43 +00:00
# Verify the headers are different
2020-02-17 19:02:24 +00:00
assert header_1 != header_2
2019-12-15 11:10:43 +00:00
# Verify the proposer is slashable
2020-02-17 19:02:24 +00:00
proposer = state.validators[header_1.proposer_index]
2019-03-19 11:12:50 +00:00
assert is_slashable_validator(proposer, get_current_epoch(state))
2019-12-15 11:10:43 +00:00
# Verify signatures
2019-11-21 22:13:45 +00:00
for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2):
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot))
2020-01-03 07:18:34 +00:00
signing_root = compute_signing_root(signed_header.message, domain)
assert bls.Verify(proposer.pubkey, signing_root, signed_header.signature)
2019-04-19 03:17:29 +00:00
2020-02-17 19:02:24 +00:00
slash_validator(state, header_1.proposer_index)
2019-03-07 19:05:34 +00:00
```
##### 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)
2019-06-30 22:10:28 +00:00
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-11-05 16:00:04 +00:00
indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
for index in sorted(indices):
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-01-19 03:06:21 +00:00
2019-03-07 19:05:34 +00:00
##### Attestations
2019-01-08 00:53:33 +00:00
2018-12-28 18:04:03 +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-06-22 20:49:53 +00:00
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
2019-12-10 00:31:43 +00:00
assert data.target.epoch == compute_epoch_at_slot(data.slot)
2019-10-12 02:48:34 +00:00
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY < = state.slot < = data.slot + SLOTS_PER_EPOCH
2020-07-24 05:26:37 +00:00
assert data.index < get_committee_count_per_slot ( state , data . target . epoch )
2019-06-13 13:46:22 +00:00
2019-10-17 01:45:07 +00:00
committee = get_beacon_committee(state, data.slot, data.index)
2019-11-02 03:02:53 +00:00
assert len(attestation.aggregation_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,
2019-10-12 02:48:34 +00:00
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)
2019-03-15 12:40:52 +00:00
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-12-15 11:10:43 +00:00
# Verify signature
2019-06-30 22:10:28 +00:00
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
2020-05-19 14:14:04 +00:00
```python
def get_validator_from_deposit(state: BeaconState, deposit: Deposit) -> Validator:
amount = deposit.data.amount
effective_balance = min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
return Validator(
pubkey=deposit.data.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=effective_balance,
)
```
2019-04-12 08:57:55 +00:00
```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(
2019-04-14 21:54:08 +00:00
leaf=hash_tree_root(deposit.data),
2019-06-30 09:02:18 +00:00
branch=deposit.proof,
2019-12-15 11:10:43 +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-12 08:57:55 +00:00
)
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
2019-04-12 08:57:55 +00:00
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]
2019-04-12 08:57:55 +00:00
if pubkey not in validator_pubkeys:
2019-12-15 11:10:43 +00:00
# Verify the deposit signature (proof of possession) which is not checked by the deposit contract
2019-11-21 22:13:45 +00:00
deposit_message = DepositMessage(
pubkey=deposit.data.pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
2019-12-15 11:10:43 +00:00
amount=deposit.data.amount,
)
domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
2020-01-08 20:54:16 +00:00
signing_root = compute_signing_root(deposit_message, domain)
2020-01-03 07:18:34 +00:00
if not bls.Verify(pubkey, signing_root, deposit.data.signature):
2019-04-12 08:57:55 +00:00
return
2019-04-22 06:13:46 +00:00
# Add validator and balance entries
2020-05-19 14:14:04 +00:00
state.validators.append(get_validator_from_deposit(state, deposit))
2019-04-20 05:17:33 +00:00
state.balances.append(amount)
2019-04-12 08:57:55 +00:00
else:
# Increase balance by deposit amount
2019-06-11 04:15:52 +00:00
index = ValidatorIndex(validator_pubkeys.index(pubkey))
2019-04-12 08:57:55 +00:00
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-11-21 22:13:45 +00:00
def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
voluntary_exit = signed_voluntary_exit.message
validator = state.validators[voluntary_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-12-15 11:10:43 +00:00
# Verify exit has not been initiated
2019-03-10 12:49:37 +00:00
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
2019-11-21 22:13:45 +00:00
assert get_current_epoch(state) >= voluntary_exit.epoch
2019-03-19 20:43:05 +00:00
# Verify the validator has been active long enough
2020-05-05 17:44:53 +00:00
assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
2019-03-07 19:05:34 +00:00
# Verify signature
2019-11-21 22:13:45 +00:00
domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
2020-01-03 07:18:34 +00:00
signing_root = compute_signing_root(voluntary_exit, domain)
assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
2019-03-19 20:43:05 +00:00
# Initiate exit
2019-11-21 22:13:45 +00:00
initiate_validator_exit(state, voluntary_exit.validator_index)
2018-10-01 22:19:16 +00:00
```