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

1781 lines
69 KiB
Markdown
Raw Normal View History

# Ethereum 2.0 Phase 0 -- The Beacon Chain
2018-09-20 05:20:49 +00:00
2019-05-06 15:30:32 +00:00
**Notice**: This document is a work-in-progress for researchers and implementers.
2018-09-20 05:20:49 +00:00
2018-11-28 07:23:37 +00:00
## Table of contents
2018-12-01 05:29:19 +00:00
<!-- TOC -->
- [Ethereum 2.0 Phase 0 -- The Beacon Chain](#ethereum-20-phase-0----the-beacon-chain)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Notation](#notation)
- [Terminology](#terminology)
- [Custom types](#custom-types)
2018-12-01 05:29:19 +00:00
- [Constants](#constants)
2019-06-17 21:19:44 +00:00
- [Configuration](#configuration)
- [Misc](#misc)
2019-02-06 16:34:19 +00:00
- [Gwei values](#gwei-values)
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
2019-01-28 00:25:29 +00:00
- [State list lengths](#state-list-lengths)
2019-05-29 20:40:46 +00:00
- [Rewards and penalties](#rewards-and-penalties)
- [Max operations per block](#max-operations-per-block)
- [Signature domains](#signature-domains)
2019-06-09 19:41:21 +00:00
- [Containers](#containers)
2019-03-07 18:02:13 +00:00
- [Misc dependencies](#misc-dependencies)
- [`Fork`](#fork)
- [`Checkpoint`](#checkpoint)
- [`Validator`](#validator)
2019-03-07 18:02:13 +00:00
- [`Crosslink`](#crosslink)
- [`AttestationData`](#attestationdata)
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
2019-03-26 19:40:19 +00:00
- [`IndexedAttestation`](#indexedattestation)
2019-03-07 18:02:13 +00:00
- [`PendingAttestation`](#pendingattestation)
- [`Eth1Data`](#eth1data)
2019-03-08 17:13:05 +00:00
- [`HistoricalBatch`](#historicalbatch)
- [`DepositData`](#depositdata)
2019-06-05 15:50:15 +00:00
- [`BeaconBlockHeader`](#beaconblockheader)
- [Beacon operations](#beacon-operations)
2019-03-07 18:02:13 +00:00
- [`ProposerSlashing`](#proposerslashing)
- [`AttesterSlashing`](#attesterslashing)
- [`Attestation`](#attestation)
- [`Deposit`](#deposit)
- [`VoluntaryExit`](#voluntaryexit)
- [`Transfer`](#transfer)
- [Beacon blocks](#beacon-blocks)
- [`BeaconBlockBody`](#beaconblockbody)
- [`BeaconBlock`](#beaconblock)
- [Beacon state](#beacon-state)
- [`BeaconState`](#beaconstate)
- [Helper functions](#helper-functions)
2019-03-04 22:49:21 +00:00
- [`xor`](#xor)
- [`hash`](#hash)
- [`hash_tree_root`](#hash_tree_root)
2019-04-08 01:51:13 +00:00
- [`signing_root`](#signing_root)
2019-05-21 17:33:52 +00:00
- [`bls_domain`](#bls_domain)
- [`slot_to_epoch`](#slot_to_epoch)
2019-02-03 09:36:21 +00:00
- [`get_previous_epoch`](#get_previous_epoch)
- [`get_current_epoch`](#get_current_epoch)
- [`get_epoch_start_slot`](#get_epoch_start_slot)
- [`is_active_validator`](#is_active_validator)
2019-03-19 11:08:17 +00:00
- [`is_slashable_validator`](#is_slashable_validator)
- [`get_active_validator_indices`](#get_active_validator_indices)
2019-03-21 16:04:20 +00:00
- [`increase_balance`](#increase_balance)
- [`decrease_balance`](#decrease_balance)
- [`get_epoch_committee_count`](#get_epoch_committee_count)
- [`get_shard_delta`](#get_shard_delta)
- [`get_epoch_start_shard`](#get_epoch_start_shard)
2019-05-05 18:30:55 +00:00
- [`get_attestation_data_slot`](#get_attestation_data_slot)
2019-04-24 04:23:51 +00:00
- [`get_block_root_at_slot`](#get_block_root_at_slot)
- [`get_block_root`](#get_block_root)
- [`get_randao_mix`](#get_randao_mix)
- [`get_active_index_root`](#get_active_index_root)
- [`generate_seed`](#generate_seed)
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
- [`verify_merkle_branch`](#verify_merkle_branch)
2019-04-30 10:34:57 +00:00
- [`get_shuffled_index`](#get_shuffled_index)
2019-05-01 14:21:38 +00:00
- [`compute_committee`](#compute_committee)
- [`get_crosslink_committee`](#get_crosslink_committee)
2019-04-18 04:20:34 +00:00
- [`get_attesting_indices`](#get_attesting_indices)
2019-05-07 09:33:51 +00:00
- [`int_to_bytes`](#int_to_bytes)
2019-02-07 21:12:58 +00:00
- [`bytes_to_int`](#bytes_to_int)
2019-02-03 10:43:33 +00:00
- [`get_total_balance`](#get_total_balance)
- [`get_domain`](#get_domain)
2019-03-26 19:40:19 +00:00
- [`convert_to_indexed`](#convert_to_indexed)
- [`validate_indexed_attestation`](#validate_indexed_attestation)
2019-05-01 06:42:49 +00:00
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
- [`integer_squareroot`](#integer_squareroot)
2019-02-20 07:45:19 +00:00
- [`get_delayed_activation_exit_epoch`](#get_delayed_activation_exit_epoch)
2019-04-14 03:14:05 +00:00
- [`get_churn_limit`](#get_churn_limit)
- [`bls_verify`](#bls_verify)
- [`bls_verify_multiple`](#bls_verify_multiple)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
2019-01-29 04:32:36 +00:00
- [Routines for updating validator status](#routines-for-updating-validator-status)
- [`initiate_validator_exit`](#initiate_validator_exit)
2019-02-12 12:24:19 +00:00
- [`slash_validator`](#slash_validator)
2019-05-05 16:15:05 +00:00
- [Genesis](#genesis)
- [Genesis trigger](#genesis-trigger)
2019-05-05 16:15:05 +00:00
- [Genesis state](#genesis-state)
- [Genesis block](#genesis-block)
2018-12-01 05:29:19 +00:00
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
2019-05-01 12:29:03 +00:00
- [Epoch processing](#epoch-processing)
2019-03-02 06:40:43 +00:00
- [Helper functions](#helper-functions-1)
- [Justification and finalization](#justification-and-finalization)
2019-01-29 13:17:05 +00:00
- [Crosslinks](#crosslinks)
2019-05-29 20:40:46 +00:00
- [Rewards and penalties](#rewards-and-penalties-1)
- [Registry updates](#registry-updates)
2019-04-06 10:07:03 +00:00
- [Slashings](#slashings)
2019-01-29 13:17:05 +00:00
- [Final updates](#final-updates)
2019-05-01 12:29:03 +00:00
- [Block processing](#block-processing)
2019-03-07 19:05:34 +00:00
- [Block header](#block-header)
- [RANDAO](#randao)
2019-04-18 08:53:02 +00:00
- [Eth1 data](#eth1-data)
- [Operations](#operations)
2019-03-08 17:34:51 +00:00
- [Proposer slashings](#proposer-slashings)
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Voluntary exits](#voluntary-exits)
- [Transfers](#transfers)
2018-12-01 05:29:19 +00:00
<!-- /TOC -->
2018-11-28 07:23:37 +00:00
## Introduction
2018-09-20 05:20:49 +00:00
This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain.
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](#dfn-validator). In the initial deployment phases of Ethereum 2.0, the only mechanism to become a [validator](#dfn-validator) is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a [validator](#dfn-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.
2018-09-20 05:20:49 +00:00
The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block and proof-of-stake votes for a beacon block. A sufficient number of attestations for the same shard block create a "crosslink", confirming the shard segment up to that shard block into the beacon chain. Crosslinks also serve as infrastructure for asynchronous cross-shard communication.
2018-09-20 05:20:49 +00:00
2018-11-29 01:56:25 +00:00
## Notation
Code snippets appearing in `this style` are to be interpreted as Python code.
2018-11-28 07:23:37 +00:00
## Terminology
2018-09-20 05:20:49 +00:00
2019-05-06 15:30:32 +00:00
* **Validator**<a id="dfn-validator"></a>—a registered participant in the beacon chain. You can become one by sending ether into the Ethereum 1.0 deposit contract.
* **Active validator**<a id="dfn-active-validator"></a>—an active participant in the Ethereum 2.0 consensus invited to, among other things, propose and attest to blocks and vote for crosslinks.
* **Committee**—a (pseudo-) randomly sampled subset of [active validators](#dfn-active-validator). When a committee is referred to collectively, as in "this committee attests to X", this is assumed to mean "some subset of that committee that contains enough [validators](#dfn-validator) that the protocol recognizes it as representing the committee".
* **Proposer**—the [validator](#dfn-validator) that creates a beacon chain block.
* **Attester**—a [validator](#dfn-validator) that is part of a committee that needs to sign off on a beacon chain block while simultaneously creating a link (crosslink) to a recent shard block on a particular shard chain.
* **Beacon chain**—the central proof-of-stake chain that is the base of the sharding system.
2019-05-06 15:30:32 +00:00
* **Shard chain**—one of the chains on which user transactions take place and account data is stored.
* **Block root**—a 32-byte Merkle root of a beacon chain block or shard chain block. Previously called "block hash".
* **Crosslink**—a set of signatures from a committee attesting to a block in a shard chain that can be included into the beacon chain. Crosslinks are the main means by which the beacon chain "learns about" the updated state of shard chains.
* **Slot**—a period during which one proposer has the ability to create a beacon chain block and some attesters have the ability to make attestations.
* **Epoch**—an aligned span of slots during which all [validators](#dfn-validator) get exactly one chance to make an attestation.
* **Finalized**, **justified**—see the [Casper FFG paper](https://arxiv.org/abs/1710.09437).
* **Withdrawal period**—the number of slots between a [validator](#dfn-validator) exit and the [validator](#dfn-validator) balance being withdrawable.
* **Genesis time**—the Unix time of the genesis beacon chain block at slot 0.
2018-09-20 05:20:49 +00:00
## Custom types
We define the following Python custom types for type hinting and readability:
| Name | SSZ equivalent | Description |
| - | - | - |
| `Slot` | `uint64` | a slot number |
| `Epoch` | `uint64` | an epoch number |
| `Shard` | `uint64` | a shard number |
| `ValidatorIndex` | `uint64` | a validator registry index |
| `Gwei` | `uint64` | an amount in Gwei |
2019-06-15 21:32:52 +00:00
| `Version` | `Bytes4` | a fork version number |
2019-06-17 21:21:45 +00:00
| `Hash` | `Bytes32` | a hashed result |
| `BLSPubkey` | `Bytes48` | a BLS12-381 public key |
| `BLSSignature` | `Bytes96` | a BLS12-381 signature |
2018-11-28 07:23:37 +00:00
## Constants
2018-09-20 05:20:49 +00:00
2019-06-17 21:19:44 +00:00
The following values are (non-configurable) constants used throughout the specification.
| Name | Value |
| - | - |
2019-06-18 14:24:23 +00:00
| `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` |
| `ZERO_HASH` | `Hash(b'\x00' * 32)` |
| `BASE_REWARDS_PER_EPOCH` | `5` |
2019-06-17 21:19:44 +00:00
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
## Configuration
*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/constant_presets) directory. These configurations are updated for releases and may be out of sync during `dev` changes.
2019-04-03 02:35:40 +00:00
### Misc
2019-02-12 13:37:30 +00:00
| Name | Value |
| - | - |
2019-02-12 13:37:30 +00:00
| `SHARD_COUNT` | `2**10` (= 1,024) |
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
2019-04-18 04:20:34 +00:00
| `MAX_INDICES_PER_ATTESTATION` | `2**12` (= 4,096) |
2019-04-14 03:14:05 +00:00
| `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) |
2019-04-14 07:28:45 +00:00
| `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) |
2019-05-06 15:30:32 +00:00
| `SHUFFLE_ROUND_COUNT` | `90` |
2019-06-28 11:23:22 +00:00
| `JUSTIFICATION_BITS_LENGTH` | `4` |
* For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)
2019-02-06 16:34:19 +00:00
### Gwei values
| Name | Value |
2019-06-21 20:30:22 +00:00
| - | - |
| `MIN_DEPOSIT_AMOUNT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) |
| `MAX_EFFECTIVE_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) |
| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) |
| `EFFECTIVE_BALANCE_INCREMENT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) |
### Initial values
| Name | Value |
| - | - |
| `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` |
2019-05-07 09:57:41 +00:00
| `BLS_WITHDRAWAL_PREFIX` | `0` |
### Time parameters
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
| `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 6 seconds |
2019-02-12 22:38:29 +00:00
| `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
| `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes |
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
2019-05-05 11:10:39 +00:00
| `MAX_EPOCHS_PER_CROSSLINK` | `2**6` (= 64) | epochs | ~7 hours |
2019-04-18 01:52:14 +00:00
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes |
2019-03-19 16:21:17 +00:00
* `MAX_EPOCHS_PER_CROSSLINK` should be a small constant times `SHARD_COUNT // SLOTS_PER_EPOCH`.
2019-03-19 16:21:17 +00:00
2019-01-28 00:25:29 +00:00
### State list lengths
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
| `EPOCHS_PER_HISTORICAL_VECTOR` | `2**16` (= 65,536) | epochs | ~0.8 years |
| `EPOCHS_PER_SLASHINGS_VECTOR` | `2**13` (= 8,192) | epochs | ~36 days |
2019-06-24 21:38:36 +00:00
| `HISTORICAL_ROOTS_LIMIT` | `2**24` (= 16,777,216) | historical roots | ~26,131 years |
| `VALIDATOR_REGISTRY_LIMIT` | `2**40` (= 1,099,511,627,776) | validator spots | |
2019-05-29 20:40:46 +00:00
### Rewards and penalties
2018-10-03 07:27:39 +00:00
| Name | Value |
| - | - |
Tweak inclusion delay rewards and set BASE_REWARD_FACTOR Substantive changes: 1) Split the inclusion delay reward between attester and proposer to add up to at most one base reward. This is analogous to the reward logic in `slash_validator`, and makes the `BASE_REWARDS_PER_EPOCH` constant include proposer rewards. 2) Double `BASE_REWARD_FACTOR` to 2^6 (addressing item 4 in #1054). When the total effective balance is 2^17 ETH then maximum annual issuance is a bit below 2^21 ETH. Maximum annual issuance happens when a) all validators make perfect attestations (matching source, target, head, as well as consistent crosslink data), b) all attestations are included as fast as possible (in particular, no skip blocks), and c) there are no slashings. ```python BASE_REWARD_FACTOR = 2**6 SLOTS_PER_EPOCH = 2**6 SECONDS_PER_SLOT = 6 BASE_REWARDS_PER_EPOCH = 5 GWEI_PER_ETH = 10**9 MAX_TOTAL_EFFECTIVE_BALANCE = 2**27 * GWEI_PER_ETH TARGET_MAX_ISSUANCE = 2**21 * GWEI_PER_ETH def integer_squareroot(n: int) -> int: """ The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``. """ assert n >= 0 x = n y = (x + 1) // 2 while y < x: x = y y = (x + n // x) // 2 return x MAX_REWARDS_PER_EPOCH = MAX_TOTAL_EFFECTIVE_BALANCE * BASE_REWARD_FACTOR // integer_squareroot(MAX_TOTAL_EFFECTIVE_BALANCE) // BASE_REWARDS_PER_EPOCH EPOCHS_PER_YEAR = 365.25*24*60*60 / (SECONDS_PER_SLOT * SLOTS_PER_EPOCH) MAX_REWARDS_PER_YEAR = EPOCHS_PER_YEAR * MAX_REWARDS_PER_EPOCH * BASE_REWARDS_PER_EPOCH print(MAX_REWARDS_PER_YEAR / TARGET_MAX_ISSUANCE) ```
2019-06-10 14:14:32 +00:00
| `BASE_REWARD_FACTOR` | `2**6` (= 64) |
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `2**9` (= 512) |
2019-03-26 13:21:49 +00:00
| `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) |
| `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) |
2019-04-22 06:34:50 +00:00
| `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) |
2018-10-03 07:27:39 +00:00
* 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](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)`; so after `INVERSE_SQRT_E_DROP_TIME` epochs, it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
### Max operations per block
2018-10-04 13:16:31 +00:00
2018-12-07 01:02:23 +00:00
| Name | Value |
2018-12-07 01:07:26 +00:00
| - | - |
2018-12-07 01:02:23 +00:00
| `MAX_PROPOSER_SLASHINGS` | `2**4` (= 16) |
| `MAX_ATTESTER_SLASHINGS` | `2**0` (= 1) |
2018-12-07 01:02:23 +00:00
| `MAX_ATTESTATIONS` | `2**7` (= 128) |
| `MAX_DEPOSITS` | `2**4` (= 16) |
2019-02-12 12:24:19 +00:00
| `MAX_VOLUNTARY_EXITS` | `2**4` (= 16) |
| `MAX_TRANSFERS` | `0` |
2018-10-04 13:16:31 +00:00
### Signature domains
2018-11-20 01:13:58 +00:00
2018-12-10 19:55:11 +00:00
| Name | Value |
| - | - |
2019-03-31 16:48:44 +00:00
| `DOMAIN_BEACON_PROPOSER` | `0` |
2019-03-03 11:04:28 +00:00
| `DOMAIN_RANDAO` | `1` |
| `DOMAIN_ATTESTATION` | `2` |
| `DOMAIN_DEPOSIT` | `3` |
| `DOMAIN_VOLUNTARY_EXIT` | `4` |
| `DOMAIN_TRANSFER` | `5` |
2019-06-09 19:41:21 +00:00
## Containers
The following types are [SimpleSerialize (SSZ)](../simple-serialize.md) containers.
*Note*: The definitions are ordered topologically to facilitate execution of the spec.
*Note*: Fields missing in container instantiations default to their zero value.
2019-03-07 18:02:13 +00:00
### Misc dependencies
2019-03-07 18:02:13 +00:00
#### `Fork`
```python
class Fork(Container):
2019-06-15 21:32:52 +00:00
previous_version: Version
current_version: Version
epoch: Epoch # Epoch of latest fork
```
#### `Checkpoint`
```python
class Checkpoint(Container):
epoch: Epoch
root: Hash
```
#### `Validator`
2018-12-06 23:51:01 +00:00
```python
class Validator(Container):
2019-06-15 21:23:44 +00:00
pubkey: BLSPubkey
withdrawal_credentials: Hash # Commitment to pubkey for withdrawals and transfers
effective_balance: Gwei # Balance at stake
slashed: boolean
2019-06-09 19:41:21 +00:00
# Status epochs
activation_eligibility_epoch: Epoch # When criteria for activation were met
activation_epoch: Epoch
exit_epoch: Epoch
2019-06-15 16:05:01 +00:00
withdrawable_epoch: Epoch # When validator can withdraw or transfer funds
2018-12-06 23:51:01 +00:00
```
2019-03-07 18:02:13 +00:00
#### `Crosslink`
2018-09-20 05:20:49 +00:00
```python
class Crosslink(Container):
shard: Shard
2019-06-09 19:41:21 +00:00
parent_root: Hash
# Crosslinking data
start_epoch: Epoch
end_epoch: Epoch
2019-06-17 21:21:45 +00:00
data_root: Hash
2018-12-06 23:51:01 +00:00
```
2019-03-07 18:02:13 +00:00
#### `AttestationData`
```python
class AttestationData(Container):
2019-03-12 10:17:34 +00:00
# LMD GHOST vote
2019-06-17 21:21:45 +00:00
beacon_block_root: Hash
2019-03-12 10:17:34 +00:00
# FFG vote
2019-06-22 20:49:53 +00:00
source: Checkpoint
target: Checkpoint
2019-03-12 10:17:34 +00:00
# Crosslink vote
crosslink: Crosslink
```
2019-03-07 18:02:13 +00:00
#### `AttestationDataAndCustodyBit`
```python
class AttestationDataAndCustodyBit(Container):
data: AttestationData
custody_bit: bit # Challengeable bit (SSZ-bool, 1 byte) for the custody of crosslink data
```
2019-03-26 19:40:19 +00:00
#### `IndexedAttestation`
2018-12-07 01:02:23 +00:00
2019-03-07 18:02:13 +00:00
```python
class IndexedAttestation(Container):
custody_bit_0_indices: List[ValidatorIndex, MAX_INDICES_PER_ATTESTATION] # Indices with custody bit equal to 0
custody_bit_1_indices: List[ValidatorIndex, MAX_INDICES_PER_ATTESTATION] # Indices with custody bit equal to 1
data: AttestationData
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2019-03-07 18:02:13 +00:00
```
#### `PendingAttestation`
```python
class PendingAttestation(Container):
2019-06-28 11:23:22 +00:00
aggregation_bits: Bitlist[MAX_INDICES_PER_ATTESTATION]
data: AttestationData
2019-06-09 19:41:21 +00:00
inclusion_delay: Slot
proposer_index: ValidatorIndex
2019-03-07 18:02:13 +00:00
```
#### `Eth1Data`
```python
class Eth1Data(Container):
2019-06-17 21:21:45 +00:00
deposit_root: Hash
deposit_count: uint64
2019-06-17 21:21:45 +00:00
block_hash: Hash
```
2019-03-08 17:13:05 +00:00
#### `HistoricalBatch`
```python
class HistoricalBatch(Container):
2019-06-17 21:21:45 +00:00
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
2019-03-08 17:13:05 +00:00
```
2019-03-15 11:18:06 +00:00
#### `DepositData`
```python
class DepositData(Container):
2019-06-15 21:23:44 +00:00
pubkey: BLSPubkey
2019-06-17 21:21:45 +00:00
withdrawal_credentials: Hash
amount: Gwei
2019-06-15 21:23:44 +00:00
signature: BLSSignature
```
2019-03-07 18:02:13 +00:00
#### `BeaconBlockHeader`
```python
class BeaconBlockHeader(Container):
slot: Slot
2019-06-17 21:21:45 +00:00
parent_root: Hash
state_root: Hash
body_root: Hash
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2019-03-07 18:02:13 +00:00
```
2019-05-14 05:15:03 +00:00
### Beacon operations
2019-03-07 18:02:13 +00:00
#### `ProposerSlashing`
```python
class ProposerSlashing(Container):
proposer_index: ValidatorIndex
header_1: BeaconBlockHeader
header_2: BeaconBlockHeader
2019-03-07 18:02:13 +00:00
```
#### `AttesterSlashing`
```python
class AttesterSlashing(Container):
attestation_1: IndexedAttestation
attestation_2: IndexedAttestation
2019-03-07 18:02:13 +00:00
```
#### `Attestation`
```python
class Attestation(Container):
2019-06-28 11:23:22 +00:00
aggregation_bits: Bitlist[MAX_INDICES_PER_ATTESTATION]
data: AttestationData
2019-06-28 11:23:22 +00:00
custody_bits: Bitlist[MAX_INDICES_PER_ATTESTATION]
2019-06-15 21:23:44 +00:00
signature: BLSSignature
```
2019-03-07 18:02:13 +00:00
#### `Deposit`
2019-03-07 18:02:13 +00:00
```python
class Deposit(Container):
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Merkle path to deposit root
data: DepositData
2019-03-07 18:02:13 +00:00
```
#### `VoluntaryExit`
2018-12-07 01:02:23 +00:00
```python
class VoluntaryExit(Container):
epoch: Epoch # Earliest epoch when voluntary exit can be processed
validator_index: ValidatorIndex
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2018-12-07 01:02:23 +00:00
```
2019-03-07 18:02:13 +00:00
#### `Transfer`
```python
class Transfer(Container):
sender: ValidatorIndex
recipient: ValidatorIndex
amount: Gwei
fee: Gwei
slot: Slot # Slot at which transfer must be processed
pubkey: BLSPubkey # Withdrawal pubkey
signature: BLSSignature # Signature checked against withdrawal pubkey
```
2019-03-07 18:02:13 +00:00
### Beacon blocks
2018-12-07 01:02:23 +00:00
2019-03-07 18:02:13 +00:00
#### `BeaconBlockBody`
```python
class BeaconBlockBody(Container):
2019-06-15 21:23:44 +00:00
randao_reveal: BLSSignature
eth1_data: Eth1Data # Eth1 data vote
graffiti: Bytes32 # Arbitrary data
2019-06-09 19:41:21 +00:00
# Operations
2019-06-20 18:03:11 +00:00
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]
attestations: List[Attestation, MAX_ATTESTATIONS]
deposits: List[Deposit, MAX_DEPOSITS]
voluntary_exits: List[VoluntaryExit, MAX_VOLUNTARY_EXITS]
transfers: List[Transfer, MAX_TRANSFERS]
2019-03-03 11:04:28 +00:00
```
2019-03-07 18:02:13 +00:00
#### `BeaconBlock`
2019-03-03 11:04:28 +00:00
```python
class BeaconBlock(Container):
slot: Slot
2019-06-17 21:21:45 +00:00
parent_root: Hash
state_root: Hash
body: BeaconBlockBody
2019-06-15 21:23:44 +00:00
signature: BLSSignature
```
2019-03-07 18:02:13 +00:00
### Beacon state
2018-09-20 05:20:49 +00:00
#### `BeaconState`
2018-09-20 05:20:49 +00:00
```python
class BeaconState(Container):
2019-06-09 19:41:21 +00:00
# Versioning
genesis_time: uint64
2019-06-09 19:41:21 +00:00
slot: Slot
fork: Fork
# History
2019-06-15 14:09:50 +00:00
latest_block_header: BeaconBlockHeader
2019-06-09 19:41:21 +00:00
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
2019-06-24 21:38:36 +00:00
historical_roots: List[Hash, HISTORICAL_ROOTS_LIMIT]
2019-06-09 19:41:21 +00:00
# Eth1
eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data, SLOTS_PER_ETH1_VOTING_PERIOD]
2019-06-09 19:41:21 +00:00
eth1_deposit_index: uint64
# Registry
2019-06-24 21:38:36 +00:00
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
2019-06-09 19:41:21 +00:00
# Shuffling
start_shard: Shard
randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR]
2019-06-22 05:29:25 +00:00
active_index_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Active registry digests for light clients
2019-06-09 19:41:21 +00:00
# Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
2019-06-09 19:41:21 +00:00
# Attestations
previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
2019-06-09 19:41:21 +00:00
# Crosslinks
previous_crosslinks: Vector[Crosslink, SHARD_COUNT] # Previous epoch snapshot
2019-06-09 19:41:21 +00:00
current_crosslinks: Vector[Crosslink, SHARD_COUNT]
# Finality
2019-06-28 11:23:22 +00:00
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
previous_justified_checkpoint: Checkpoint # Previous epoch snapshot
current_justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
2018-09-20 05:20:49 +00:00
```
## Helper functions
2019-05-06 15:30:32 +00:00
*Note*: The definitions below are for specification purposes and are not necessarily optimal implementations.
2019-03-04 22:49:21 +00:00
### `xor`
```python
def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32:
return Bytes32(a ^ b for a, b in zip(bytes1, bytes2))
2019-03-04 22:49:21 +00:00
```
### `hash`
The `hash` function is SHA256.
2019-05-06 15:30:32 +00:00
*Note*: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethereum 2.0 deployment phase.
### `hash_tree_root`
`def hash_tree_root(object: SSZSerializable) -> Hash` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the [SimpleSerialize spec](../simple-serialize.md#merkleization).
2019-04-08 01:51:13 +00:00
### `signing_root`
2019-02-15 00:23:03 +00:00
`def signing_root(object: Container) -> Hash` is a function for computing signing messages, as defined in the [SimpleSerialize spec](../simple-serialize.md#self-signed-containers).
2019-02-15 00:23:03 +00:00
### `bls_domain`
```python
def bls_domain(domain_type: int, fork_version: bytes=b'\x00\x00\x00\x00') -> int:
"""
Return the bls domain given by the ``domain_type`` and optional 4 byte ``fork_version`` (defaults to zero).
"""
return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
```
### `slot_to_epoch`
```python
2019-01-31 15:58:31 +00:00
def slot_to_epoch(slot: Slot) -> Epoch:
2019-01-30 09:25:39 +00:00
"""
2019-01-30 15:01:38 +00:00
Return the epoch number of the given ``slot``.
2019-01-30 09:25:39 +00:00
"""
return Epoch(slot // SLOTS_PER_EPOCH)
```
2019-02-03 09:36:21 +00:00
### `get_previous_epoch`
```python
2019-02-12 12:24:19 +00:00
def get_previous_epoch(state: BeaconState) -> Epoch:
2019-02-03 09:36:21 +00:00
"""`
Return the previous epoch of the given ``state``.
Return the current epoch if it's genesis epoch.
2019-02-03 09:36:21 +00:00
"""
current_epoch = get_current_epoch(state)
return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1)
2019-02-03 09:36:21 +00:00
```
### `get_current_epoch`
2018-09-20 05:20:49 +00:00
2019-01-26 14:31:09 +00:00
```python
2019-01-31 15:58:31 +00:00
def get_current_epoch(state: BeaconState) -> Epoch:
2019-01-30 09:25:39 +00:00
"""
2019-01-30 15:01:38 +00:00
Return the current epoch of the given ``state``.
2019-01-30 09:25:39 +00:00
"""
2019-01-26 14:31:09 +00:00
return slot_to_epoch(state.slot)
```
2018-09-20 05:20:49 +00:00
### `get_epoch_start_slot`
2019-01-27 14:54:46 +00:00
```python
2019-01-31 15:58:31 +00:00
def get_epoch_start_slot(epoch: Epoch) -> Slot:
2019-01-30 09:25:39 +00:00
"""
2019-01-30 15:01:38 +00:00
Return the starting slot of the given ``epoch``.
2019-01-30 09:25:39 +00:00
"""
return Slot(epoch * SLOTS_PER_EPOCH)
2019-01-27 14:54:46 +00:00
```
2018-12-14 15:29:49 +00:00
### `is_active_validator`
2019-04-24 04:23:51 +00:00
2018-12-12 19:00:53 +00:00
```python
2019-01-31 15:58:31 +00:00
def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
"""
2019-01-30 15:01:38 +00:00
Check if ``validator`` is active.
"""
return validator.activation_epoch <= epoch < validator.exit_epoch
```
2019-03-19 11:08:17 +00:00
### `is_slashable_validator`
2019-04-24 04:23:51 +00:00
2019-03-19 11:08:17 +00:00
```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)
2019-03-19 11:08:17 +00:00
```
### `get_active_validator_indices`
2018-09-20 05:20:49 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> Sequence[ValidatorIndex]:
"""
2019-04-14 07:28:45 +00:00
Get active validator indices at ``epoch``.
"""
2019-06-17 21:51:00 +00:00
return [ValidatorIndex(i) for i, v in enumerate(state.validators) if is_active_validator(v, epoch)]
2018-09-20 05:20:49 +00:00
```
2019-03-21 16:04:20 +00:00
### `increase_balance`
2019-03-21 16:04:20 +00:00
```python
2019-03-22 04:56:54 +00:00
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
"""
2019-04-20 05:17:33 +00:00
Increase validator balance by ``delta``.
2019-03-22 04:56:54 +00:00
"""
2019-04-20 05:17:33 +00:00
state.balances[index] += delta
2019-03-21 16:04:20 +00:00
```
2019-03-21 16:04:20 +00:00
### `decrease_balance`
2019-03-21 16:04:20 +00:00
```python
2019-03-22 04:56:54 +00:00
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
"""
2019-04-20 05:17:33 +00:00
Decrease validator balance by ``delta`` with underflow protection.
2019-03-22 04:56:54 +00:00
"""
2019-04-22 06:34:50 +00:00
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
2019-03-21 16:04:20 +00:00
```
### `get_epoch_committee_count`
2019-01-08 00:53:33 +00:00
```python
def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int:
2019-01-30 09:25:39 +00:00
"""
2019-04-23 14:16:52 +00:00
Return the number of committees at ``epoch``.
2019-01-30 09:25:39 +00:00
"""
2019-04-24 04:23:51 +00:00
active_validator_indices = get_active_validator_indices(state, epoch)
2019-01-08 00:53:33 +00:00
return max(
1,
min(
2019-02-12 22:38:29 +00:00
SHARD_COUNT // SLOTS_PER_EPOCH,
2019-04-24 04:23:51 +00:00
len(active_validator_indices) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE,
2019-01-08 00:53:33 +00:00
)
2019-02-12 22:38:29 +00:00
) * SLOTS_PER_EPOCH
2019-01-08 00:53:33 +00:00
```
### `get_shard_delta`
```python
def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:
"""
2019-06-09 19:41:21 +00:00
Return the number of shards to increment ``state.start_shard`` during ``epoch``.
"""
return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH)
```
### `get_epoch_start_shard`
2018-09-20 05:20:49 +00:00
```python
def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
assert epoch <= get_current_epoch(state) + 1
check_epoch = Epoch(get_current_epoch(state) + 1)
2019-06-17 21:51:00 +00:00
shard = Shard((state.start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT)
while check_epoch > epoch:
check_epoch -= Epoch(1)
shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT)
return shard
```
2019-05-05 18:30:55 +00:00
### `get_attestation_data_slot`
2019-01-08 00:53:33 +00:00
```python
2019-05-05 18:30:55 +00:00
def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot:
2019-06-22 20:49:53 +00:00
committee_count = get_epoch_committee_count(state, data.target.epoch)
offset = (data.crosslink.shard + SHARD_COUNT - get_epoch_start_shard(state, data.target.epoch)) % SHARD_COUNT
return Slot(get_epoch_start_slot(data.target.epoch) + offset // (committee_count // SLOTS_PER_EPOCH))
```
2018-09-20 05:20:49 +00:00
2019-04-24 04:23:51 +00:00
### `get_block_root_at_slot`
```python
2019-04-24 04:23:51 +00:00
def get_block_root_at_slot(state: BeaconState,
2019-06-17 21:21:45 +00:00
slot: Slot) -> Hash:
"""
2019-01-30 15:01:38 +00:00
Return the block root at a recent ``slot``.
"""
2019-03-03 11:04:28 +00:00
assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
2019-06-09 19:41:21 +00:00
return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
2018-09-20 05:20:49 +00:00
```
2019-04-24 04:23:51 +00:00
### `get_block_root`
2019-03-04 18:45:41 +00:00
```python
2019-04-24 04:23:51 +00:00
def get_block_root(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
2019-03-04 18:45:41 +00:00
"""
2019-04-24 04:23:51 +00:00
Return the block root at a recent ``epoch``.
2019-03-04 18:45:41 +00:00
"""
2019-04-24 04:23:51 +00:00
return get_block_root_at_slot(state, get_epoch_start_slot(epoch))
2019-03-04 18:45:41 +00:00
```
2018-09-20 05:20:49 +00:00
### `get_randao_mix`
```python
def get_randao_mix(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
"""
2019-01-30 15:01:38 +00:00
Return the randao mix at a recent ``epoch``.
``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch].
"""
return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
```
### `get_active_index_root`
```python
def get_active_index_root(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
"""
2019-01-30 15:01:38 +00:00
Return the index root at a recent ``epoch``.
``epoch`` expected to be between
(current_epoch - EPOCHS_PER_HISTORICAL_VECTOR + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY].
"""
return state.active_index_roots[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
```
### `generate_seed`
```python
def generate_seed(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
"""
2019-01-26 00:33:15 +00:00
Generate a seed for the given ``epoch``.
"""
return hash(
get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) +
get_active_index_root(state, epoch) +
2019-05-07 09:33:51 +00:00
int_to_bytes(epoch, length=32)
)
```
### `get_beacon_proposer_index`
```python
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
"""
2019-04-30 11:27:45 +00:00
Return the current beacon proposer index.
"""
2019-04-30 11:27:45 +00:00
epoch = get_current_epoch(state)
committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH
offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH)
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
first_committee = get_crosslink_committee(state, epoch, shard)
2019-04-24 04:23:51 +00:00
MAX_RANDOM_BYTE = 2**8 - 1
seed = generate_seed(state, epoch)
2019-03-14 18:57:17 +00:00
i = 0
while True:
2019-04-30 11:27:45 +00:00
candidate_index = first_committee[(epoch + i) % len(first_committee)]
2019-05-07 09:33:51 +00:00
random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
2019-06-09 19:41:21 +00:00
effective_balance = state.validators[candidate_index].effective_balance
2019-04-24 04:46:28 +00:00
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
return ValidatorIndex(candidate_index)
i += 1
```
### `verify_merkle_branch`
```python
2019-06-22 16:12:42 +00:00
def verify_merkle_branch(leaf: Hash, proof: Sequence[Hash], depth: int, index: int, root: Hash) -> bool:
"""
2019-03-02 01:01:40 +00:00
Verify that the given ``leaf`` is on the merkle branch ``proof``
starting with the given ``root``.
"""
value = leaf
for i in range(depth):
if index // (2**i) % 2:
2019-03-02 01:01:40 +00:00
value = hash(proof[i] + value)
else:
2019-03-02 01:01:40 +00:00
value = hash(value + proof[i])
return value == root
```
2019-04-30 10:34:57 +00:00
### `get_shuffled_index`
```python
2019-06-09 19:41:21 +00:00
def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Hash) -> ValidatorIndex:
2019-04-30 10:34:57 +00:00
"""
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
"""
assert index < index_count
assert index_count <= 2**40
# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
# See the 'generalized domain' algorithm on page 3
for current_round in range(SHUFFLE_ROUND_COUNT):
pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count
2019-06-17 21:51:00 +00:00
flip = ValidatorIndex((pivot + index_count - index) % index_count)
2019-04-30 10:34:57 +00:00
position = max(index, flip)
2019-06-17 21:51:00 +00:00
source = hash(
seed + int_to_bytes(current_round, length=1) +
2019-06-18 20:00:22 +00:00
int_to_bytes(position // 256, length=4)
2019-06-17 21:51:00 +00:00
)
2019-04-30 10:34:57 +00:00
byte = source[(position % 256) // 8]
bit = (byte >> (position % 8)) % 2
index = flip if bit else index
return ValidatorIndex(index)
2019-04-30 10:34:57 +00:00
```
2019-05-01 14:21:38 +00:00
### `compute_committee`
```python
2019-06-22 16:12:42 +00:00
def compute_committee(indices: Sequence[ValidatorIndex],
seed: Hash, index: int, count: int) -> Sequence[ValidatorIndex]:
2019-05-01 14:21:38 +00:00
start = (len(indices) * index) // count
end = (len(indices) * (index + 1)) // count
return [indices[get_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
```
2019-05-01 08:09:24 +00:00
### `get_crosslink_committee`
```python
2019-06-22 16:12:42 +00:00
def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> Sequence[ValidatorIndex]:
2019-05-01 14:21:38 +00:00
return compute_committee(
indices=get_active_validator_indices(state, epoch),
seed=generate_seed(state, epoch),
index=(shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) % SHARD_COUNT,
count=get_epoch_committee_count(state, epoch),
)
2019-05-01 08:09:24 +00:00
```
2019-04-18 04:20:34 +00:00
### `get_attesting_indices`
```python
2019-04-18 04:20:34 +00:00
def get_attesting_indices(state: BeaconState,
data: AttestationData,
bits: Bitlist[MAX_INDICES_PER_ATTESTATION]) -> Set[ValidatorIndex]:
"""
Return the set of attesting indices corresponding to ``data`` and ``bitfield``.
"""
2019-06-22 20:49:53 +00:00
committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard)
return set(index for i, index in enumerate(committee) if bits[i])
```
2019-05-07 09:33:51 +00:00
### `int_to_bytes`
2019-05-07 09:33:51 +00:00
```python
def int_to_bytes(integer: int, length: int) -> bytes:
return integer.to_bytes(length, 'little')
```
2018-09-20 05:20:49 +00:00
2019-02-07 21:12:58 +00:00
### `bytes_to_int`
```python
def bytes_to_int(data: bytes) -> int:
return int.from_bytes(data, 'little')
```
2018-09-20 05:20:49 +00:00
2019-02-03 10:43:33 +00:00
### `get_total_balance`
2019-02-03 10:14:02 +00:00
```python
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
2019-02-03 10:14:02 +00:00
"""
Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
2019-02-03 10:14:02 +00:00
"""
2019-06-17 21:51:00 +00:00
return Gwei(max(sum([state.validators[index].effective_balance for index in indices]), 1))
2019-02-03 10:14:02 +00:00
```
### `get_domain`
```python
def get_domain(state: BeaconState,
domain_type: int,
message_epoch: Epoch=None) -> int:
2019-01-30 09:25:39 +00:00
"""
2019-04-02 18:30:26 +00:00
Return the signature domain (fork version concatenated with domain type) of a message.
2019-01-30 09:25:39 +00:00
"""
2019-04-02 18:30:26 +00:00
epoch = get_current_epoch(state) if message_epoch is None else message_epoch
fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
return bls_domain(domain_type, fork_version)
```
2019-03-26 19:40:19 +00:00
### `convert_to_indexed`
2018-12-07 01:02:23 +00:00
```python
def convert_to_indexed(state: BeaconState, attestation: Attestation) -> IndexedAttestation:
2019-01-23 13:52:52 +00:00
"""
2019-04-03 19:24:46 +00:00
Convert ``attestation`` to (almost) indexed-verifiable form.
2019-01-23 13:52:52 +00:00
"""
2019-06-28 11:23:22 +00:00
attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bits)
custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_bits)
assert custody_bit_1_indices.issubset(attesting_indices)
custody_bit_0_indices = attesting_indices.difference(custody_bit_1_indices)
2019-03-26 19:40:19 +00:00
return IndexedAttestation(
custody_bit_0_indices=sorted(custody_bit_0_indices),
custody_bit_1_indices=sorted(custody_bit_1_indices),
data=attestation.data,
signature=attestation.signature,
)
```
### `validate_indexed_attestation`
```python
def validate_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> None:
"""
Verify validity of ``indexed_attestation``.
"""
bit_0_indices = indexed_attestation.custody_bit_0_indices
bit_1_indices = indexed_attestation.custody_bit_1_indices
2019-04-03 00:04:12 +00:00
# Verify no index has custody bit equal to 1 [to be removed in phase 1]
assert len(bit_1_indices) == 0
# Verify max number of indices
assert len(bit_0_indices) + len(bit_1_indices) <= MAX_INDICES_PER_ATTESTATION
# Verify index sets are disjoint
assert len(set(bit_0_indices).intersection(bit_1_indices)) == 0
# Verify indices are sorted
assert bit_0_indices == sorted(bit_0_indices) and bit_1_indices == sorted(bit_1_indices)
# Verify aggregate signature
assert bls_verify_multiple(
pubkeys=[
2019-06-09 19:41:21 +00:00
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_0_indices]),
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_1_indices]),
],
message_hashes=[
2019-03-26 19:40:19 +00:00
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)),
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)),
],
2019-04-17 00:16:01 +00:00
signature=indexed_attestation.signature,
2019-06-22 20:49:53 +00:00
domain=get_domain(state, DOMAIN_ATTESTATION, indexed_attestation.data.target.epoch),
)
2018-12-07 01:02:23 +00:00
```
2019-05-01 06:42:49 +00:00
### `is_slashable_attestation_data`
```python
2019-05-01 06:42:49 +00:00
def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
"""
2019-05-01 06:42:49 +00:00
Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules.
"""
return (
2019-05-01 07:45:29 +00:00
# Double vote
2019-06-22 20:49:53 +00:00
(data_1 != data_2 and data_1.target.epoch == data_2.target.epoch) or
2019-05-01 07:45:29 +00:00
# Surround vote
2019-06-22 20:49:53 +00:00
(data_1.source.epoch < data_2.source.epoch and data_2.target.epoch < data_1.target.epoch)
)
```
### `integer_squareroot`
```python
def integer_squareroot(n: int) -> int:
"""
The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``.
"""
2019-01-11 00:09:58 +00:00
assert n >= 0
x = n
y = (x + 1) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
```
2019-02-20 07:45:19 +00:00
### `get_delayed_activation_exit_epoch`
```python
2019-02-20 07:45:19 +00:00
def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
"""
2019-02-20 07:45:19 +00:00
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
"""
return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY)
```
2019-04-14 03:14:05 +00:00
### `get_churn_limit`
2018-11-16 16:41:59 +00:00
```python
2019-04-14 03:14:05 +00:00
def get_churn_limit(state: BeaconState) -> int:
2019-05-01 23:26:18 +00:00
"""
Return the churn limit based on the active validator count.
"""
2019-04-14 03:14:05 +00:00
return max(
MIN_PER_EPOCH_CHURN_LIMIT,
2019-04-14 07:28:45 +00:00
len(get_active_validator_indices(state, get_current_epoch(state))) // CHURN_LIMIT_QUOTIENT
)
2019-04-14 06:49:17 +00:00
```
2019-03-12 17:07:20 +00:00
### `bls_verify`
`bls_verify` is a function for verifying a BLS signature, as defined in the [BLS Signature spec](../bls_signature.md#bls_verify).
2018-12-10 19:55:11 +00:00
### `bls_verify_multiple`
2019-03-11 16:28:39 +00:00
`bls_verify_multiple` is a function for verifying a BLS signature constructed from multiple messages, as defined in the [BLS Signature spec](../bls_signature.md#bls_verify_multiple).
### `bls_aggregate_pubkeys`
`bls_aggregate_pubkeys` is a function for aggregating multiple BLS public keys into a single aggregate key, as defined in the [BLS Signature spec](../bls_signature.md#bls_aggregate_pubkeys).
2018-12-05 18:40:08 +00:00
### Routines for updating validator status
2019-05-06 15:30:32 +00:00
*Note*: All functions in this section mutate `state`.
2018-12-10 22:42:28 +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
"""
Initiate the exit of the validator of the given ``index``.
2019-01-30 09:25:39 +00:00
"""
2019-04-14 09:01:53 +00:00
# Return if validator already initiated exit
2019-06-09 19:41:21 +00:00
validator = state.validators[index]
2019-04-13 23:13:53 +00:00
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return
2019-04-14 09:01:53 +00:00
# Compute exit queue epoch
2019-06-09 19:41:21 +00:00
exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
2019-04-20 08:13:45 +00:00
exit_queue_epoch = max(exit_epochs + [get_delayed_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-04-14 08:50:05 +00:00
if exit_queue_churn >= get_churn_limit(state):
exit_queue_epoch += Epoch(1)
2018-12-11 15:49:50 +00:00
2019-04-13 23:13:53 +00:00
# Set validator exit epoch and withdrawable epoch
2019-04-14 08:10:44 +00:00
validator.exit_epoch = exit_queue_epoch
validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
```
2019-02-12 12:24:19 +00:00
#### `slash_validator`
```python
def slash_validator(state: BeaconState,
slashed_index: ValidatorIndex,
whistleblower_index: ValidatorIndex=None) -> None:
2019-01-30 09:25:39 +00:00
"""
Slash the validator with index ``slashed_index``.
2019-01-30 09:25:39 +00:00
"""
epoch = get_current_epoch(state)
2019-03-29 07:26:26 +00:00
initiate_validator_exit(state, slashed_index)
validator = state.validators[slashed_index]
validator.slashed = True
validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR))
state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT)
# Apply proposer and whistleblower rewards
proposer_index = get_beacon_proposer_index(state)
if whistleblower_index is None:
whistleblower_index = proposer_index
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
increase_balance(state, proposer_index, proposer_reward)
increase_balance(state, whistleblower_index, whistleblower_reward - proposer_reward)
```
2019-05-05 16:15:05 +00:00
## Genesis
2018-09-20 05:20:49 +00:00
### Genesis trigger
2019-03-03 11:04:28 +00:00
2019-06-22 16:12:42 +00:00
Before genesis has been triggered and whenever the deposit contract emits a `Deposit` log, call the function `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where:
2019-05-05 16:15:05 +00:00
* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log
* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log
2019-03-03 11:04:28 +00:00
When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let:
2019-05-05 16:15:05 +00:00
* `genesis_deposits = deposits`
* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400`
* `genesis_eth1_data` be the object of type `Eth1Data` where:
2019-06-11 14:29:34 +00:00
* `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits`
2019-06-09 10:03:38 +00:00
* `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits`
* `genesis_eth1_data.deposit_count = len(genesis_deposits)`
2019-03-03 11:04:28 +00:00
*Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder:
2019-05-05 16:15:05 +00:00
```python
2019-06-22 16:12:42 +00:00
def is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool:
# Process deposits
state = BeaconState()
for deposit in deposits:
process_deposit(state, deposit)
# Count active validators at genesis
active_validator_count = 0
for validator in state.validators:
2019-06-09 10:03:38 +00:00
if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
active_validator_count += 1
# Check effective balance to trigger genesis
2019-06-09 10:03:38 +00:00
GENESIS_ACTIVE_VALIDATOR_COUNT = 2**16
return active_validator_count == GENESIS_ACTIVE_VALIDATOR_COUNT
```
2019-05-05 16:15:05 +00:00
### Genesis state
Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_data)`.
2018-11-16 16:41:59 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth1_data: Eth1Data) -> BeaconState:
state = BeaconState(
genesis_time=genesis_time,
eth1_data=eth1_data,
latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
)
2018-10-09 07:33:22 +00:00
2019-02-12 12:24:19 +00:00
# Process genesis deposits
2019-05-05 16:15:05 +00:00
for deposit in deposits:
2019-02-15 00:23:03 +00:00
process_deposit(state, deposit)
2018-12-10 21:16:06 +00:00
2019-02-12 12:24:19 +00:00
# Process genesis activations
2019-06-09 19:41:21 +00:00
for validator in state.validators:
2019-04-24 04:46:28 +00:00
if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = GENESIS_EPOCH
validator.activation_epoch = GENESIS_EPOCH
2018-12-10 21:16:06 +00:00
2019-06-28 11:23:22 +00:00
# Populate active_index_roots
2019-06-22 16:12:42 +00:00
genesis_active_index_root = hash_tree_root(
2019-06-24 21:38:36 +00:00
List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, GENESIS_EPOCH))
2019-06-22 16:12:42 +00:00
)
for index in range(EPOCHS_PER_HISTORICAL_VECTOR):
2019-06-09 19:41:21 +00:00
state.active_index_roots[index] = genesis_active_index_root
2018-12-10 21:16:06 +00:00
return state
```
2018-09-20 05:20:49 +00:00
2019-05-05 16:15:05 +00:00
### Genesis block
Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`.
## Beacon chain state transition function
2019-05-08 18:15:23 +00:00
The post-state corresponding to a pre-state `state` and a block `block` is defined as `state_transition(state, block)`. State transitions that trigger an unhandled excpetion (e.g. a failed `assert` or an out-of-range list access) are considered invalid.
2019-05-01 12:14:10 +00:00
```python
2019-05-13 20:53:28 +00:00
def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
2019-05-08 18:15:23 +00:00
# Process slots (including those with no blocks) since block
process_slots(state, block.slot)
# Process block
process_block(state, block)
2019-05-14 05:15:03 +00:00
# Validate state root (`validate_state_root == True` in production)
2019-05-13 20:53:28 +00:00
if validate_state_root:
2019-05-14 05:15:03 +00:00
assert block.state_root == hash_tree_root(state)
2019-05-08 18:15:23 +00:00
# Return post-state
2019-05-02 10:07:25 +00:00
return state
2019-05-01 12:14:10 +00:00
```
2018-09-20 05:20:49 +00:00
2019-05-03 20:21:42 +00:00
```python
def process_slots(state: BeaconState, slot: Slot) -> None:
assert state.slot <= slot
2019-05-03 20:21:42 +00:00
while state.slot < slot:
process_slot(state)
2019-05-03 21:22:19 +00:00
# Process epoch on the first slot of the next epoch
2019-05-03 20:21:42 +00:00
if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
process_epoch(state)
state.slot += Slot(1)
2019-05-03 20:21:42 +00:00
```
2019-03-03 11:04:28 +00:00
```python
2019-05-03 20:21:42 +00:00
def process_slot(state: BeaconState) -> None:
# Cache state root
2019-05-01 13:16:55 +00:00
previous_state_root = hash_tree_root(state)
2019-06-09 19:41:21 +00:00
state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
2019-05-03 20:21:42 +00:00
# Cache latest block header state root
if state.latest_block_header.state_root == ZERO_HASH:
2019-05-01 13:16:55 +00:00
state.latest_block_header.state_root = previous_state_root
2019-05-03 20:21:42 +00:00
# Cache block root
2019-05-01 14:07:55 +00:00
previous_block_root = signing_root(state.latest_block_header)
2019-06-09 19:41:21 +00:00
state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
2019-03-03 11:04:28 +00:00
```
2018-09-20 05:20:49 +00:00
2019-05-01 12:29:03 +00:00
### Epoch processing
*Note*: The `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
2019-05-01 12:14:10 +00:00
```python
2019-05-01 12:29:03 +00:00
def process_epoch(state: BeaconState) -> None:
2019-05-01 12:14:10 +00:00
process_justification_and_finalization(state)
process_crosslinks(state)
process_rewards_and_penalties(state)
process_registry_updates(state)
2019-05-24 14:51:21 +00:00
# @process_reveal_deadlines
# @process_challenge_deadlines
2019-05-01 12:14:10 +00:00
process_slashings(state)
process_final_updates(state)
2019-05-24 14:51:21 +00:00
# @after_process_final_updates
2019-05-01 12:14:10 +00:00
```
2019-03-07 19:05:34 +00:00
#### Helper functions
2019-03-03 11:04:28 +00:00
```python
def get_total_active_balance(state: BeaconState) -> Gwei:
2019-06-22 16:12:42 +00:00
return get_total_balance(state, set(get_active_validator_indices(state, get_current_epoch(state))))
2019-03-03 11:04:28 +00:00
```
2018-09-20 05:20:49 +00:00
2019-03-07 19:05:34 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
2019-06-23 09:09:09 +00:00
assert epoch in (get_previous_epoch(state), get_current_epoch(state))
2019-04-20 05:17:33 +00:00
return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations
2019-03-07 19:05:34 +00:00
```
2019-03-03 11:04:28 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_matching_target_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
2019-03-07 19:05:34 +00:00
return [
2019-04-20 05:17:33 +00:00
a for a in get_matching_source_attestations(state, epoch)
2019-06-22 20:49:53 +00:00
if a.data.target.root == get_block_root(state, epoch)
2019-03-07 19:05:34 +00:00
]
2019-03-03 11:04:28 +00:00
```
2019-03-07 19:05:34 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> Sequence[PendingAttestation]:
2019-03-07 19:05:34 +00:00
return [
2019-04-20 05:17:33 +00:00
a for a in get_matching_source_attestations(state, epoch)
2019-05-05 18:30:55 +00:00
if a.data.beacon_block_root == get_block_root_at_slot(state, get_attestation_data_slot(state, a.data))
2019-03-07 19:05:34 +00:00
]
```
2019-03-07 19:05:34 +00:00
```python
def get_unslashed_attesting_indices(state: BeaconState,
2019-06-22 16:12:42 +00:00
attestations: Sequence[PendingAttestation]) -> Set[ValidatorIndex]:
output = set() # type: Set[ValidatorIndex]
for a in attestations:
2019-06-28 11:23:22 +00:00
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
2019-06-22 16:12:42 +00:00
return set(filter(lambda index: not state.validators[index].slashed, list(output)))
2019-03-07 19:05:34 +00:00
```
2018-11-16 15:48:57 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_attesting_balance(state: BeaconState, attestations: Sequence[PendingAttestation]) -> Gwei:
return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
```
2019-03-07 19:05:34 +00:00
```python
def get_winning_crosslink_and_attesting_indices(state: BeaconState,
epoch: Epoch,
2019-06-22 16:12:42 +00:00
shard: Shard) -> Tuple[Crosslink, Set[ValidatorIndex]]:
2019-05-06 16:34:03 +00:00
attestations = [a for a in get_matching_source_attestations(state, epoch) if a.data.crosslink.shard == shard]
crosslinks = list(filter(
2019-05-06 19:49:46 +00:00
lambda c: hash_tree_root(state.current_crosslinks[shard]) in (c.parent_root, hash_tree_root(c)),
2019-05-06 16:34:03 +00:00
[a.data.crosslink for a in attestations]
2019-04-18 09:33:38 +00:00
))
2019-05-06 16:34:03 +00:00
# Winning crosslink has the crosslink data root with the most balance voting for it (ties broken lexicographically)
winning_crosslink = max(crosslinks, key=lambda c: (
2019-05-06 17:26:14 +00:00
get_attesting_balance(state, [a for a in attestations if a.data.crosslink == c]), c.data_root
2019-05-06 16:34:03 +00:00
), default=Crosslink())
winning_attestations = [a for a in attestations if a.data.crosslink == winning_crosslink]
return winning_crosslink, get_unslashed_attesting_indices(state, winning_attestations)
2019-03-07 19:05:34 +00:00
```
#### Justification and finalization
2019-03-07 19:05:34 +00:00
```python
def process_justification_and_finalization(state: BeaconState) -> None:
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
2019-04-11 12:28:42 +00:00
return
2019-04-20 06:10:25 +00:00
previous_epoch = get_previous_epoch(state)
current_epoch = get_current_epoch(state)
old_previous_justified_checkpoint = state.previous_justified_checkpoint
old_current_justified_checkpoint = state.current_justified_checkpoint
2019-03-12 18:32:11 +00:00
# Process justifications
state.previous_justified_checkpoint = state.current_justified_checkpoint
state.justification_bits[1:] = state.justification_bits[: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:
state.current_justified_checkpoint = Checkpoint(epoch=previous_epoch,
root=get_block_root(state, previous_epoch))
2019-06-28 11:23:22 +00:00
state.justification_bits[1] = 0b1
2019-06-28 11:34:01 +00:00
matching_target_attestations = get_matching_target_attestations(state, current_epoch) # Current epoch
if get_attesting_balance(state, matching_target_attestations) * 3 >= get_total_active_balance(state) * 2:
state.current_justified_checkpoint = Checkpoint(epoch=current_epoch,
root=get_block_root(state, current_epoch))
2019-06-28 11:23:22 +00:00
state.justification_bits[0] = 0b1
2019-03-07 19:05:34 +00:00
# Process finalizations
2019-06-28 11:23:22 +00:00
bits = state.justification_bits
# The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
2019-06-28 11:23:22 +00:00
if all(bits[1:4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint
# The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
2019-06-28 11:23:22 +00:00
if all(bits[1:3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint
# The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
2019-06-28 11:23:22 +00:00
if all(bits[0:3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint
# The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
2019-06-28 11:23:22 +00:00
if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint
```
2018-09-20 05:20:49 +00:00
2019-03-07 19:05:34 +00:00
#### Crosslinks
2019-03-07 19:05:34 +00:00
```python
def process_crosslinks(state: BeaconState) -> None:
2019-04-18 17:16:50 +00:00
state.previous_crosslinks = [c for c in state.current_crosslinks]
for epoch in (get_previous_epoch(state), get_current_epoch(state)):
for offset in range(get_epoch_committee_count(state, epoch)):
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
2019-04-18 08:53:22 +00:00
if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee):
2019-04-18 04:20:34 +00:00
state.current_crosslinks[shard] = winning_crosslink
```
2018-12-05 11:22:15 +00:00
#### Rewards and penalties
```python
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
total_balance = get_total_active_balance(state)
2019-06-09 19:41:21 +00:00
effective_balance = state.validators[index].effective_balance
return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH)
```
```python
2019-06-22 16:12:42 +00:00
def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
2019-04-20 06:10:25 +00:00
previous_epoch = get_previous_epoch(state)
total_balance = get_total_active_balance(state)
2019-06-17 21:51:00 +00:00
rewards = [Gwei(0) for _ in range(len(state.validators))]
penalties = [Gwei(0) for _ in range(len(state.validators))]
2019-04-24 04:23:51 +00:00
eligible_validator_indices = [
2019-06-17 21:51:00 +00:00
ValidatorIndex(index) for index, v in enumerate(state.validators)
2019-04-24 04:23:51 +00:00
if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)
]
2019-04-24 04:23:51 +00:00
# Micro-incentives for matching FFG source, FFG target, and head
matching_source_attestations = get_matching_source_attestations(state, previous_epoch)
matching_target_attestations = get_matching_target_attestations(state, previous_epoch)
matching_head_attestations = get_matching_head_attestations(state, previous_epoch)
for attestations in (matching_source_attestations, matching_target_attestations, matching_head_attestations):
unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations)
2019-06-02 20:13:52 +00:00
attesting_balance = get_total_balance(state, unslashed_attesting_indices)
2019-04-24 04:23:51 +00:00
for index in eligible_validator_indices:
if index in unslashed_attesting_indices:
rewards[index] += get_base_reward(state, index) * attesting_balance // total_balance
else:
2019-04-24 04:23:51 +00:00
penalties[index] += get_base_reward(state, index)
# Proposer and inclusion delay micro-rewards
2019-04-24 05:32:43 +00:00
for index in get_unslashed_attesting_indices(state, matching_source_attestations):
index = ValidatorIndex(index)
2019-04-30 11:27:45 +00:00
attestation = min([
2019-05-03 16:34:16 +00:00
a for a in matching_source_attestations
2019-06-28 11:23:22 +00:00
if index in get_attesting_indices(state, a.data, a.aggregation_bits)
2019-04-30 11:27:45 +00:00
], key=lambda a: a.inclusion_delay)
2019-06-18 14:24:23 +00:00
proposer_reward = Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT)
Tweak inclusion delay rewards and set BASE_REWARD_FACTOR Substantive changes: 1) Split the inclusion delay reward between attester and proposer to add up to at most one base reward. This is analogous to the reward logic in `slash_validator`, and makes the `BASE_REWARDS_PER_EPOCH` constant include proposer rewards. 2) Double `BASE_REWARD_FACTOR` to 2^6 (addressing item 4 in #1054). When the total effective balance is 2^17 ETH then maximum annual issuance is a bit below 2^21 ETH. Maximum annual issuance happens when a) all validators make perfect attestations (matching source, target, head, as well as consistent crosslink data), b) all attestations are included as fast as possible (in particular, no skip blocks), and c) there are no slashings. ```python BASE_REWARD_FACTOR = 2**6 SLOTS_PER_EPOCH = 2**6 SECONDS_PER_SLOT = 6 BASE_REWARDS_PER_EPOCH = 5 GWEI_PER_ETH = 10**9 MAX_TOTAL_EFFECTIVE_BALANCE = 2**27 * GWEI_PER_ETH TARGET_MAX_ISSUANCE = 2**21 * GWEI_PER_ETH def integer_squareroot(n: int) -> int: """ The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``. """ assert n >= 0 x = n y = (x + 1) // 2 while y < x: x = y y = (x + n // x) // 2 return x MAX_REWARDS_PER_EPOCH = MAX_TOTAL_EFFECTIVE_BALANCE * BASE_REWARD_FACTOR // integer_squareroot(MAX_TOTAL_EFFECTIVE_BALANCE) // BASE_REWARDS_PER_EPOCH EPOCHS_PER_YEAR = 365.25*24*60*60 / (SECONDS_PER_SLOT * SLOTS_PER_EPOCH) MAX_REWARDS_PER_YEAR = EPOCHS_PER_YEAR * MAX_REWARDS_PER_EPOCH * BASE_REWARDS_PER_EPOCH print(MAX_REWARDS_PER_YEAR / TARGET_MAX_ISSUANCE) ```
2019-06-10 14:14:32 +00:00
rewards[attestation.proposer_index] += proposer_reward
max_attester_reward = get_base_reward(state, index) - proposer_reward
2019-06-18 14:24:23 +00:00
rewards[index] += Gwei(max_attester_reward * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay)
2019-04-24 04:23:51 +00:00
# Inactivity penalty
finality_delay = previous_epoch - state.finalized_checkpoint.epoch
2019-04-24 04:23:51 +00:00
if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY:
matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations)
for index in eligible_validator_indices:
index = ValidatorIndex(index)
penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index))
2019-04-24 04:23:51 +00:00
if index not in matching_target_attesting_indices:
penalties[index] += Gwei(
2019-06-09 19:41:21 +00:00
state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
)
return rewards, penalties
```
2018-09-20 05:20:49 +00:00
```python
2019-06-22 16:12:42 +00:00
def get_crosslink_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
rewards = [Gwei(0) for _ in range(len(state.validators))]
penalties = [Gwei(0) for _ in range(len(state.validators))]
epoch = get_previous_epoch(state)
for offset in range(get_epoch_committee_count(state, epoch)):
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
attesting_balance = get_total_balance(state, attesting_indices)
committee_balance = get_total_balance(state, crosslink_committee)
for index in crosslink_committee:
base_reward = get_base_reward(state, index)
if index in attesting_indices:
rewards[index] += base_reward * attesting_balance // committee_balance
else:
penalties[index] += base_reward
return rewards, penalties
```
```python
def process_rewards_and_penalties(state: BeaconState) -> None:
2019-04-11 12:28:42 +00:00
if get_current_epoch(state) == GENESIS_EPOCH:
return
2019-04-20 05:17:33 +00:00
rewards1, penalties1 = get_attestation_deltas(state)
rewards2, penalties2 = get_crosslink_deltas(state)
2019-06-17 21:51:00 +00:00
for index in range(len(state.validators)):
increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index])
```
2018-11-23 04:54:11 +00:00
#### Registry updates
2018-12-05 11:22:15 +00:00
```python
def process_registry_updates(state: BeaconState) -> None:
# Process activation eligibility and ejections
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
if (
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
validator.effective_balance >= MAX_EFFECTIVE_BALANCE
):
validator.activation_eligibility_epoch = get_current_epoch(state)
2019-04-20 06:32:41 +00:00
if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE:
initiate_validator_exit(state, ValidatorIndex(index))
2019-03-07 19:05:34 +00:00
2019-04-22 05:16:34 +00:00
# Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
activation_queue = sorted([
2019-06-09 19:41:21 +00:00
index for index, validator in enumerate(state.validators) if
2019-04-06 10:07:03 +00:00
validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and
validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_checkpoint.epoch)
2019-06-09 19:41:21 +00:00
], key=lambda index: state.validators[index].activation_eligibility_epoch)
# Dequeued validators for activation up to churn limit (without resetting activation epoch)
2019-04-14 03:14:05 +00:00
for index in activation_queue[:get_churn_limit(state)]:
2019-06-09 19:41:21 +00:00
validator = state.validators[index]
if validator.activation_epoch == FAR_FUTURE_EPOCH:
validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
2019-03-07 19:05:34 +00:00
```
2019-04-06 10:07:03 +00:00
#### Slashings
2019-03-07 19:05:34 +00:00
```python
def process_slashings(state: BeaconState) -> None:
2019-06-22 05:34:02 +00:00
epoch = get_current_epoch(state)
total_balance = get_total_active_balance(state)
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
penalty = validator.effective_balance * min(sum(state.slashings) * 3, total_balance) // total_balance
decrease_balance(state, ValidatorIndex(index), penalty)
2019-03-07 19:05:34 +00:00
```
#### Final updates
```python
def process_final_updates(state: BeaconState) -> None:
2019-03-07 19:05:34 +00:00
current_epoch = get_current_epoch(state)
next_epoch = current_epoch + 1
# Reset eth1 data votes
if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
state.eth1_data_votes = []
# Update effective balances with hysteresis
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
balance = state.balances[index]
HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance:
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
# Update start shard
2019-06-17 21:51:00 +00:00
state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
2019-03-07 19:05:34 +00:00
# Set active index root
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % EPOCHS_PER_HISTORICAL_VECTOR
2019-06-09 19:41:21 +00:00
state.active_index_roots[index_root_position] = hash_tree_root(
2019-06-24 21:38:36 +00:00
List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](
get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY))
)
2019-03-07 19:05:34 +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
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-03-08 17:13:05 +00:00
historical_batch = HistoricalBatch(
2019-06-09 19:41:21 +00:00
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
# Verify that the parent matches
2019-05-06 19:49:46 +00:00
assert block.parent_root == signing_root(state.latest_block_header)
2019-03-07 19:05:34 +00:00
# Save current block as the new latest block
2019-04-19 08:26:54 +00:00
state.latest_block_header = BeaconBlockHeader(
slot=block.slot,
2019-05-06 19:49:46 +00:00
parent_root=block.parent_root,
state_root=ZERO_HASH, # Overwritten in 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-03-17 11:48:47 +00:00
# Verify proposer is not slashed
2019-06-09 19:41:21 +00:00
proposer = state.validators[get_beacon_proposer_index(state)]
2019-03-11 22:07:34 +00:00
assert not proposer.slashed
# Verify proposer signature
assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
2019-03-07 19:05:34 +00:00
```
#### RANDAO
```python
2019-05-03 20:21:42 +00:00
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
epoch = get_current_epoch(state)
# Verify RANDAO reveal
2019-06-09 19:41:21 +00:00
proposer = state.validators[get_beacon_proposer_index(state)]
assert bls_verify(proposer.pubkey, hash_tree_root(epoch), body.randao_reveal, get_domain(state, DOMAIN_RANDAO))
# Mix in RANDAO reveal
mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
2019-03-07 19:05:34 +00:00
```
#### Eth1 data
```python
2019-05-03 20:21:42 +00:00
def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
state.eth1_data_votes.append(body.eth1_data)
if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD:
2019-06-09 19:41:21 +00:00
state.eth1_data = body.eth1_data
2019-03-07 19:05:34 +00:00
```
#### Operations
2019-03-07 19:05:34 +00:00
```python
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
2019-05-03 20:21:42 +00:00
# Verify that outstanding deposits are processed up to the maximum number of deposits
2019-06-09 19:41:21 +00:00
assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
2019-05-03 20:21:42 +00:00
# Verify that there are no duplicate transfers
assert len(body.transfers) == len(set(body.transfers))
2019-06-18 00:54:08 +00:00
all_operations = (
(body.proposer_slashings, process_proposer_slashing),
(body.attester_slashings, process_attester_slashing),
(body.attestations, process_attestation),
(body.deposits, process_deposit),
(body.voluntary_exits, process_voluntary_exit),
(body.transfers, process_transfer),
2019-06-22 16:12:42 +00:00
) # type: Sequence[Tuple[List, Callable]]
for operations, function in all_operations:
for operation in operations:
function(state, operation)
```
2019-03-07 19:05:34 +00:00
##### Proposer slashings
2019-03-07 19:05:34 +00:00
```python
2019-05-03 20:21:42 +00:00
def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
2019-03-07 19:05:34 +00:00
"""
Process ``ProposerSlashing`` operation.
2019-03-07 19:05:34 +00:00
"""
2019-06-09 19:41:21 +00:00
proposer = state.validators[proposer_slashing.proposer_index]
# Verify that the epoch is the same
assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot)
2019-03-08 17:34:51 +00:00
# But the headers are different
assert proposer_slashing.header_1 != proposer_slashing.header_2
2019-03-19 11:08:17 +00:00
# Check proposer is slashable
2019-03-19 11:12:50 +00:00
assert is_slashable_validator(proposer, get_current_epoch(state))
2019-03-07 19:05:34 +00:00
# Signatures are valid
for header in (proposer_slashing.header_1, proposer_slashing.header_2):
2019-03-31 16:48:44 +00:00
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, slot_to_epoch(header.slot))
assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain)
2019-03-07 19:05:34 +00:00
slash_validator(state, proposer_slashing.proposer_index)
```
##### Attester slashings
2018-12-10 21:16:06 +00:00
2019-03-02 01:49:28 +00:00
```python
2019-05-03 20:21:42 +00:00
def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
2019-03-07 19:05:34 +00:00
"""
Process ``AttesterSlashing`` operation.
2019-03-07 19:05:34 +00:00
"""
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)
validate_indexed_attestation(state, attestation_1)
validate_indexed_attestation(state, attestation_2)
2019-05-01 06:42:49 +00:00
slashed_any = False
2019-04-30 09:39:18 +00:00
attesting_indices_1 = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
attesting_indices_2 = attestation_2.custody_bit_0_indices + attestation_2.custody_bit_1_indices
for index in sorted(set(attesting_indices_1).intersection(attesting_indices_2)):
2019-06-09 19:41:21 +00:00
if is_slashable_validator(state.validators[index], get_current_epoch(state)):
2019-05-01 06:42:49 +00:00
slash_validator(state, index)
slashed_any = True
assert slashed_any
2019-03-02 01:49:28 +00:00
```
2019-03-07 19:05:34 +00:00
##### Attestations
2019-01-08 00:53:33 +00:00
```python
2019-03-07 19:05:34 +00:00
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
2019-01-30 09:25:39 +00:00
"""
Process ``Attestation`` operation.
2019-01-30 09:25:39 +00:00
"""
2019-05-05 18:30:55 +00:00
data = attestation.data
assert data.crosslink.shard < SHARD_COUNT
2019-06-22 20:49:53 +00:00
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
2019-05-05 18:30:55 +00:00
attestation_slot = get_attestation_data_slot(state, data)
2019-04-30 11:27:45 +00:00
assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH
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-04-30 11:27:45 +00:00
inclusion_delay=state.slot - attestation_slot,
2019-04-24 04:23:51 +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-05-06 17:26:14 +00:00
parent_crosslink = state.current_crosslinks[data.crosslink.shard]
2019-03-07 19:05:34 +00:00
state.current_epoch_attestations.append(pending_attestation)
else:
2019-06-23 09:18:24 +00:00
assert data.source == state.previous_justified_checkpoint
2019-05-06 17:26:14 +00:00
parent_crosslink = state.previous_crosslinks[data.crosslink.shard]
2019-03-07 19:05:34 +00:00
state.previous_epoch_attestations.append(pending_attestation)
2019-05-05 11:04:34 +00:00
2019-06-23 09:18:24 +00:00
# Check crosslink against expected parent crosslink
2019-05-06 19:49:46 +00:00
assert data.crosslink.parent_root == hash_tree_root(parent_crosslink)
assert data.crosslink.start_epoch == parent_crosslink.end_epoch
2019-06-22 20:49:53 +00:00
assert data.crosslink.end_epoch == min(data.target.epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK)
2019-05-06 17:26:14 +00:00
assert data.crosslink.data_root == ZERO_HASH # [to be removed in phase 1]
2019-06-28 11:23:22 +00:00
2019-06-23 09:18:24 +00:00
# Check signature
validate_indexed_attestation(state, convert_to_indexed(state, attestation))
2019-02-12 12:24:19 +00:00
```
2019-03-07 19:05:34 +00:00
##### Deposits
```python
def process_deposit(state: BeaconState, deposit: Deposit) -> None:
"""
2019-04-20 06:32:41 +00:00
Process an Eth1 deposit, registering a validator or increasing its balance.
"""
# Verify the Merkle branch
2019-04-20 06:32:41 +00:00
assert verify_merkle_branch(
leaf=hash_tree_root(deposit.data),
proof=deposit.proof,
depth=DEPOSIT_CONTRACT_TREE_DEPTH,
2019-06-09 19:41:21 +00:00
index=state.eth1_deposit_index,
root=state.eth1_data.deposit_root,
)
2019-04-20 06:35:02 +00:00
# Deposits must be processed in order
2019-06-09 19:41:21 +00:00
state.eth1_deposit_index += 1
pubkey = deposit.data.pubkey
amount = deposit.data.amount
2019-06-09 19:41:21 +00:00
validator_pubkeys = [v.pubkey for v in state.validators]
if pubkey not in validator_pubkeys:
# Verify the deposit signature (proof of possession).
2019-05-30 01:53:46 +00:00
# Invalid signatures are allowed by the deposit contract,
# and hence included on-chain, but must not be processed.
# Note: Deposits are valid across forks, hence the deposit domain is retrieved directly from `bls_domain`
if not bls_verify(
pubkey, signing_root(deposit.data), deposit.data.signature, bls_domain(DOMAIN_DEPOSIT)
):
return
# Add validator and balance entries
2019-06-09 19:41:21 +00:00
state.validators.append(Validator(
pubkey=pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
activation_epoch=FAR_FUTURE_EPOCH,
exit_epoch=FAR_FUTURE_EPOCH,
withdrawable_epoch=FAR_FUTURE_EPOCH,
effective_balance=min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
))
2019-04-20 05:17:33 +00:00
state.balances.append(amount)
else:
# Increase balance by deposit amount
index = ValidatorIndex(validator_pubkeys.index(pubkey))
increase_balance(state, index, amount)
```
2019-03-07 19:05:34 +00:00
##### Voluntary exits
2019-02-12 12:24:19 +00:00
```python
2019-03-10 12:50:28 +00:00
def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
2019-02-12 12:24:19 +00:00
"""
Process ``VoluntaryExit`` operation.
2019-02-12 12:24:19 +00:00
"""
2019-06-09 19:41:21 +00:00
validator = state.validators[exit.validator_index]
2019-03-19 21:49:01 +00:00
# Verify the validator is active
assert is_active_validator(validator, get_current_epoch(state))
2019-03-07 19:05:34 +00:00
# Verify the validator has not yet exited
assert validator.exit_epoch == FAR_FUTURE_EPOCH
2019-03-07 19:05:34 +00:00
# Exits must specify an epoch when they become valid; they are not valid before then
assert get_current_epoch(state) >= exit.epoch
2019-03-19 20:43:05 +00:00
# Verify the validator has been active long enough
assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
2019-03-07 19:05:34 +00:00
# Verify signature
domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain)
2019-03-19 20:43:05 +00:00
# Initiate exit
2019-03-07 19:05:34 +00:00
initiate_validator_exit(state, exit.validator_index)
```
2019-03-07 19:05:34 +00:00
##### Transfers
2018-09-20 05:20:49 +00:00
2019-03-02 01:49:28 +00:00
```python
2019-03-07 19:05:34 +00:00
def process_transfer(state: BeaconState, transfer: Transfer) -> None:
"""
Process ``Transfer`` operation.
2019-03-07 19:05:34 +00:00
"""
# Verify the balance the covers amount and fee (with overflow protection)
assert state.balances[transfer.sender] >= max(transfer.amount + transfer.fee, transfer.amount, transfer.fee)
2019-03-07 19:05:34 +00:00
# A transfer is valid in only one slot
assert state.slot == transfer.slot
# Sender must satisfy at least one of the following conditions in the parenthesis:
2019-03-07 19:05:34 +00:00
assert (
# * Has not been activated
2019-06-09 19:41:21 +00:00
state.validators[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
# * Is withdrawable
2019-06-09 19:41:21 +00:00
get_current_epoch(state) >= state.validators[transfer.sender].withdrawable_epoch or
# * Balance after transfer is more than the effective balance threshold
2019-04-24 05:17:25 +00:00
transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender]
2019-03-02 01:49:28 +00:00
)
2019-03-07 19:05:34 +00:00
# Verify that the pubkey is valid
assert (
2019-06-09 19:41:21 +00:00
state.validators[transfer.sender].withdrawal_credentials ==
2019-05-07 09:57:41 +00:00
int_to_bytes(BLS_WITHDRAWAL_PREFIX, length=1) + hash(transfer.pubkey)[1:]
2019-03-07 19:05:34 +00:00
)
# Verify that the signature is valid
assert bls_verify(transfer.pubkey, signing_root(transfer), transfer.signature, get_domain(state, DOMAIN_TRANSFER))
2019-03-07 19:05:34 +00:00
# Process the transfer
decrease_balance(state, transfer.sender, transfer.amount + transfer.fee)
increase_balance(state, transfer.recipient, transfer.amount)
increase_balance(state, get_beacon_proposer_index(state), transfer.fee)
# Verify balances are not dust
2019-04-20 05:17:33 +00:00
assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT)
assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT)
2019-03-02 01:49:28 +00:00
```