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 -->
- [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 )
2019-06-15 20:57:50 +00:00
- [Custom types ](#custom-types )
2018-12-01 05:29:19 +00:00
- [Constants ](#constants )
2019-06-17 21:19:44 +00:00
- [Configuration ](#configuration )
2018-12-04 10:57:09 +00:00
- [Misc ](#misc )
2019-02-06 16:34:19 +00:00
- [Gwei values ](#gwei-values )
2018-12-04 10:57:09 +00:00
- [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 )
2019-03-31 05:02:10 +00:00
- [Max operations per block ](#max-operations-per-block )
2018-12-04 10:57:09 +00:00
- [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 )
2019-01-17 11:18:30 +00:00
- [`Fork` ](#fork )
2019-06-21 22:33:43 +00:00
- [`Checkpoint` ](#checkpoint )
2019-06-05 05:52:09 +00:00
- [`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 )
2019-06-05 05:52:09 +00:00
- [`Eth1Data` ](#eth1data )
2019-03-08 17:13:05 +00:00
- [`HistoricalBatch` ](#historicalbatch )
2019-06-05 05:52:09 +00:00
- [`DepositData` ](#depositdata )
2019-06-05 15:50:15 +00:00
- [`BeaconBlockHeader` ](#beaconblockheader )
2019-03-31 05:02:10 +00:00
- [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 )
2019-01-28 19:15:43 +00:00
- [Helper functions ](#helper-functions )
2019-03-04 22:49:21 +00:00
- [`xor` ](#xor )
2019-01-28 19:15:43 +00:00
- [`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 )
2019-01-28 19:15:43 +00:00
- [`slot_to_epoch` ](#slot_to_epoch )
2019-02-03 09:36:21 +00:00
- [`get_previous_epoch` ](#get_previous_epoch )
2019-01-28 19:15:43 +00:00
- [`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 )
2019-01-28 19:15:43 +00:00
- [`get_active_validator_indices` ](#get_active_validator_indices )
2019-03-21 16:04:20 +00:00
- [`increase_balance` ](#increase_balance )
- [`decrease_balance` ](#decrease_balance )
2019-01-28 19:15:43 +00:00
- [`get_epoch_committee_count` ](#get_epoch_committee_count )
2019-04-30 07:09:52 +00:00
- [`get_shard_delta` ](#get_shard_delta )
2019-04-29 16:02:39 +00:00
- [`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 )
2019-01-28 19:15:43 +00:00
- [`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 )
2019-03-01 03:07:10 +00:00
- [`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 )
2019-04-29 16:02:39 +00:00
- [`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 )
2019-01-28 19:15:43 +00:00
- [`get_domain` ](#get_domain )
2019-03-26 19:40:19 +00:00
- [`convert_to_indexed` ](#convert_to_indexed )
2019-05-07 16:34:19 +00:00
- [`validate_indexed_attestation` ](#validate_indexed_attestation )
2019-05-01 06:42:49 +00:00
- [`is_slashable_attestation_data` ](#is_slashable_attestation_data )
2019-01-28 19:15:43 +00:00
- [`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 )
2019-01-28 19:15:43 +00:00
- [`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 )
2019-01-28 19:15:43 +00:00
- [`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 )
2019-06-08 18:00:50 +00:00
- [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 )
2019-04-18 09:08:34 +00:00
- [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 )
2019-04-18 09:08:34 +00:00
- [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 )
2019-03-31 05:02:10 +00:00
- [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
2018-11-14 21:01:57 +00:00
This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain.
2019-03-27 19:00:28 +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 ](#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
2019-03-27 19:00:28 +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
2019-02-11 21:30:36 +00:00
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.
2019-06-25 13:32:56 +00:00
* **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
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 |
| `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 |
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 |
| - | - |
2019-06-18 14:24:23 +00:00
| `FAR_FUTURE_EPOCH` | `Epoch(2**64 - 1)` |
| `ZERO_HASH` | `Hash(b'\x00' * 32)` |
2019-06-17 22:12:47 +00:00
| `BASE_REWARDS_PER_EPOCH` | `5` |
2019-06-17 21:19:44 +00:00
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
## Configuration
2019-06-25 13:32:56 +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/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
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
| - | - |
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` |
2018-11-30 14:28:33 +00:00
2019-06-25 13:32:56 +00:00
* For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111 ](https://vitalik.ca/files/Ithaca201807_Sharding.pdf ); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE` ), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE` . (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)
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 |
| - | - |
2019-06-11 04:15:52 +00:00
| `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` |
2019-05-07 09:57:41 +00:00
| `BLS_WITHDRAWAL_PREFIX` | `0` |
2018-12-04 10:57:09 +00:00
### Time parameters
2018-11-30 14:28:33 +00:00
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
2019-06-09 20:30:42 +00:00
| `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 |
2019-01-31 02:22:25 +00:00
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
2019-01-31 15:56:48 +00:00
| `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes |
2019-04-17 04:30:03 +00:00
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
2019-03-08 22:16:06 +00:00
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
2019-02-20 15:58:25 +00:00
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
2019-03-08 22:16:06 +00:00
| `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
2019-06-25 13:32:56 +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
2019-01-28 05:12:37 +00:00
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
2019-06-19 19:59:44 +00:00
| `EPOCHS_PER_HISTORICAL_VECTOR` | `2**16` (= 65,536) | epochs | ~0.8 years |
| `EPOCHS_PER_SLASHED_BALANCES_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 | |
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 |
| - | - |
2019-06-10 14:14:32 +00:00
| `BASE_REWARD_FACTOR` | `2**6` (= 64) |
2019-03-25 14:30:59 +00:00
| `WHISTLEBLOWING_REWARD_QUOTIENT` | `2**9` (= 512) |
2019-03-26 13:21:49 +00:00
| `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) |
2019-04-17 04:06:28 +00:00
| `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) |
2019-04-22 06:34:50 +00:00
| `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) |
2018-10-03 07:27:39 +00:00
2019-06-25 13:32:56 +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)` .
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) |
2019-01-28 20:33:50 +00:00
| `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) |
2019-04-19 08:09:29 +00:00
| `MAX_TRANSFERS` | `0` |
2018-10-04 13:16:31 +00:00
2018-12-04 10:57:09 +00:00
### Signature domains
2018-11-20 01:13:58 +00:00
2018-12-10 19:55:11 +00:00
| Name | Value |
2018-11-30 14:28:33 +00:00
| - | - |
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` |
2019-03-04 02:14:03 +00:00
| `DOMAIN_TRANSFER` | `5` |
2018-11-30 14:28:33 +00:00
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.
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
```
2019-06-21 22:33:43 +00:00
#### `Checkpoint`
```python
class Checkpoint(Container):
epoch: Epoch
root: Hash
```
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-06-15 14:51:17 +00:00
withdrawal_credentials: Hash # Commitment to pubkey for withdrawals and transfers
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-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
2019-05-27 18:29:53 +00:00
class Crosslink(Container):
2019-06-11 04:15:52 +00:00
shard: Shard
2019-06-09 19:41:21 +00:00
parent_root: Hash
# Crosslinking data
2019-06-11 04:15:52 +00:00
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`
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-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
2019-05-12 21:56:53 +00:00
crosslink: Crosslink
2018-10-02 02:21:15 +00:00
```
2019-03-07 18:02:13 +00:00
#### `AttestationDataAndCustodyBit`
2018-12-23 10:48:11 +00:00
```python
2019-05-27 18:29:53 +00:00
class AttestationDataAndCustodyBit(Container):
2019-05-12 21:56:53 +00:00
data: AttestationData
2019-06-27 08:51:06 +00:00
custody_bit: bit # Challengeable bit (SSZ-bool, 1 byte) for the custody of crosslink data
2018-12-23 10:48:11 +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-06-20 18:05:34 +00:00
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
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-28 11:23:22 +00:00
aggregation_bits: Bitlist[MAX_INDICES_PER_ATTESTATION]
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-06-17 21:21:45 +00:00
deposit_root: Hash
2019-06-05 05:57:54 +00:00
deposit_count: uint64
2019-06-17 21:21:45 +00:00
block_hash: Hash
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-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`
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-06-17 21:21:45 +00:00
withdrawal_credentials: Hash
2019-06-11 04:15:52 +00:00
amount: Gwei
2019-06-15 21:23:44 +00:00
signature: BLSSignature
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
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
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-06-11 04:15:52 +00:00
proposer_index: ValidatorIndex
2019-05-12 21:56:53 +00:00
header_1: BeaconBlockHeader
header_2: BeaconBlockHeader
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-28 11:23:22 +00:00
aggregation_bits: Bitlist[MAX_INDICES_PER_ATTESTATION]
2019-05-12 21:56:53 +00:00
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
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-06-15 14:51:17 +00:00
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # 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-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`
2019-02-12 22:41:38 +00:00
```python
2019-05-27 18:29:53 +00:00
class Transfer(Container):
2019-06-11 04:15:52 +00:00
sender: ValidatorIndex
recipient: ValidatorIndex
amount: Gwei
fee: Gwei
2019-06-15 14:51:17 +00:00
slot: Slot # Slot at which transfer must be processed
pubkey: BLSPubkey # Withdrawal pubkey
signature: BLSSignature # Signature checked against withdrawal pubkey
2019-02-12 22:41:38 +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]
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
2019-05-27 18:29:53 +00:00
class BeaconBlock(Container):
2019-06-11 04:15:52 +00:00
slot: Slot
2019-06-17 21:21:45 +00:00
parent_root: Hash
state_root: Hash
2019-05-12 21:56:53 +00:00
body: BeaconBlockBody
2019-06-15 21:23:44 +00:00
signature: BLSSignature
2018-11-20 07:40:04 +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
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
2019-06-20 18:05:34 +00:00
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
2019-06-19 19:59:44 +00:00
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
2019-06-22 05:29:25 +00:00
slashed_balances: Vector[Gwei, EPOCHS_PER_SLASHED_BALANCES_VECTOR] # 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
# Crosslinks
2019-06-15 14:51:17 +00:00
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
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-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-03-04 22:49:21 +00:00
### `xor`
```python
def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32:
2019-05-27 18:29:53 +00:00
return Bytes32(a ^ b for a, b in zip(bytes1, bytes2))
2019-03-04 22:49:21 +00:00
```
2019-01-28 19:15:43 +00:00
### `hash`
2018-12-04 11:47:41 +00:00
2019-03-15 10:51:08 +00:00
The `hash` function is SHA256.
2018-12-04 11:47:41 +00:00
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.
2018-12-04 11:47:41 +00:00
2019-01-28 19:15:43 +00:00
### `hash_tree_root`
2018-12-04 11:47:41 +00:00
2019-06-25 13:32:56 +00:00
`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 ).
2018-12-04 11:47:41 +00:00
2019-04-08 01:51:13 +00:00
### `signing_root`
2019-02-15 00:23:03 +00:00
2019-06-25 13:32:56 +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
2019-05-21 17:30:38 +00:00
### `bls_domain`
```python
2019-05-22 20:52:44 +00:00
def bls_domain(domain_type: int, fork_version: bytes=b'\x00\x00\x00\x00') -> int:
2019-05-21 17:30:38 +00:00
"""
2019-05-21 23:35:24 +00:00
Return the bls domain given by the ``domain_type`` and optional 4 byte ``fork_version`` (defaults to zero).
2019-05-21 17:30:38 +00:00
"""
return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
```
2019-01-28 19:15:43 +00:00
### `slot_to_epoch`
2018-12-04 10:57:09 +00:00
```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
"""
2019-06-11 04:15:52 +00:00
return Epoch(slot // SLOTS_PER_EPOCH)
2018-12-04 10:57:09 +00:00
```
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``.
2019-04-14 12:12:39 +00:00
Return the current epoch if it's 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-01-28 19:15:43 +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-11-22 13:24:20 +00:00
```
2018-09-20 05:20:49 +00:00
2019-01-28 19:15:43 +00:00
### `get_epoch_start_slot`
2018-12-11 20:30:28 +00:00
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
"""
2019-06-11 04:15:52 +00:00
return Slot(epoch * SLOTS_PER_EPOCH)
2019-01-27 14:54:46 +00:00
```
2018-12-14 15:29:49 +00:00
2019-01-28 19:15:43 +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:
2018-12-07 12:18:55 +00:00
"""
2019-01-30 15:01:38 +00:00
Check if ``validator`` is active.
2018-12-07 12:18:55 +00:00
"""
2019-01-26 15:16:32 +00:00
return validator.activation_epoch < = epoch < validator.exit_epoch
2018-12-07 12:18:55 +00:00
```
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.
"""
2019-06-20 21:02:22 +00:00
return (not validator.slashed) and (validator.activation_epoch < = epoch < validator.withdrawable_epoch )
2019-03-19 11:08:17 +00:00
```
2019-01-28 19:15:43 +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-04-14 07:28:45 +00:00
Get 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-03-21 16:04:20 +00:00
### `increase_balance`
2019-03-07 07:38:03 +00:00
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-07 07:38:03 +00:00
2019-03-21 16:04:20 +00:00
### `decrease_balance`
2019-03-07 07:38:03 +00:00
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
```
2019-03-07 07:38:03 +00:00
2019-01-28 19:15:43 +00:00
### `get_epoch_committee_count`
2019-01-08 00:53:33 +00:00
```python
2019-04-09 10:52:32 +00:00
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
```
2019-04-30 07:09:52 +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``.
2019-04-30 07:09:52 +00:00
"""
return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH)
```
2019-04-29 16:02:39 +00:00
### `get_epoch_start_shard`
2018-09-20 05:20:49 +00:00
```python
2019-04-29 16:02:39 +00:00
def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
2019-04-30 07:09:52 +00:00
assert epoch < = get_current_epoch(state) + 1
2019-06-18 19:57:37 +00:00
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)
2019-04-30 07:09:52 +00:00
while check_epoch > epoch:
2019-06-18 19:57:37 +00:00
check_epoch -= Epoch(1)
shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT)
2019-04-30 07:09:52 +00:00
return shard
2019-04-29 16:02:39 +00:00
```
2019-01-23 21:41:25 +00:00
2019-05-05 18:30:55 +00:00
### `get_attestation_data_slot`
2019-01-08 00:53:33 +00:00
2019-04-29 16:02:39 +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-11-30 14:28:33 +00:00
```
2018-09-20 05:20:49 +00:00
2019-04-24 04:23:51 +00:00
### `get_block_root_at_slot`
2018-11-30 14:28:33 +00:00
```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:
2018-11-30 14:28:33 +00:00
"""
2019-01-30 15:01:38 +00:00
Return the block root at a recent ``slot``.
2018-11-30 14:28:33 +00:00
"""
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
2019-01-28 19:15:43 +00:00
### `get_randao_mix`
2019-01-10 17:01:19 +00:00
```python
def get_randao_mix(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
2019-01-10 17:01:19 +00:00
"""
2019-01-30 15:01:38 +00:00
Return the randao mix at a recent ``epoch``.
2019-06-19 19:59:44 +00:00
``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch].
2019-01-10 17:01:19 +00:00
"""
2019-06-19 19:59:44 +00:00
return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
2019-01-10 17:01:19 +00:00
```
2019-01-28 19:15:43 +00:00
### `get_active_index_root`
2019-01-19 03:06:21 +00:00
```python
def get_active_index_root(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
2019-01-19 03:06:21 +00:00
"""
2019-01-30 15:01:38 +00:00
Return the index root at a recent ``epoch``.
2019-05-03 00:11:11 +00:00
``epoch`` expected to be between
2019-06-19 19:59:44 +00:00
(current_epoch - EPOCHS_PER_HISTORICAL_VECTOR + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY].
2019-01-19 03:06:21 +00:00
"""
2019-06-19 19:59:44 +00:00
return state.active_index_roots[epoch % EPOCHS_PER_HISTORICAL_VECTOR]
2019-01-19 03:06:21 +00:00
```
2019-01-28 19:15:43 +00:00
### `generate_seed`
2019-01-25 23:07:54 +00:00
```python
def generate_seed(state: BeaconState,
2019-06-17 21:21:45 +00:00
epoch: Epoch) -> Hash:
2019-01-10 17:01:19 +00:00
"""
2019-01-26 00:33:15 +00:00
Generate a seed for the given ``epoch``.
2019-01-10 17:01:19 +00:00
"""
2019-01-25 23:07:54 +00:00
return hash(
2019-06-19 19:59:44 +00:00
get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) +
2019-02-02 05:02:09 +00:00
get_active_index_root(state, epoch) +
2019-05-07 09:33:51 +00:00
int_to_bytes(epoch, length=32)
2019-01-25 23:07:54 +00:00
)
2019-01-10 17:01:19 +00:00
```
2019-01-28 19:15:43 +00:00
### `get_beacon_proposer_index`
2018-11-20 07:40:04 +00:00
```python
2019-04-17 02:32:50 +00:00
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
2018-11-30 14:28:33 +00:00
"""
2019-04-30 11:27:45 +00:00
Return the current beacon proposer index.
2018-11-30 14:28:33 +00:00
"""
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
2019-04-30 18:55:14 +00:00
offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH)
2019-06-11 04:15:52 +00:00
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
2019-04-30 18:55:14 +00:00
first_committee = get_crosslink_committee(state, epoch, shard)
2019-04-24 04:23:51 +00:00
MAX_RANDOM_BYTE = 2**8 - 1
2019-05-01 22:19:21 +00:00
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:
2019-06-11 04:15:52 +00:00
return ValidatorIndex(candidate_index)
2019-03-14 02:42:49 +00:00
i += 1
2018-11-20 07:40:04 +00:00
```
2019-03-01 03:07:10 +00:00
### `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-01 03:07:10 +00:00
"""
2019-03-02 01:01:40 +00:00
Verify that the given ``leaf`` is on the merkle branch ``proof``
starting with the given ``root``.
2019-03-01 03:07:10 +00:00
"""
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)
2019-03-01 03:07:10 +00:00
else:
2019-03-02 01:01:40 +00:00
value = hash(value + proof[i])
2019-03-01 03:07:10 +00:00
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
2019-06-11 04:15:52 +00:00
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
2019-06-11 04:15:52 +00:00
return ValidatorIndex(index)
2019-04-30 10:34:57 +00:00
```
2019-05-01 14:21:38 +00:00
### `compute_committee`
2019-04-29 16:02:39 +00:00
```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
2019-06-11 04:15:52 +00:00
return [indices[get_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
2019-04-29 16:02:39 +00:00
```
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`
2019-03-27 14:31:56 +00:00
```python
2019-04-18 04:20:34 +00:00
def get_attesting_indices(state: BeaconState,
2019-06-28 07:36:45 +00:00
data: AttestationData,
2019-06-28 11:23:22 +00:00
bits: Bitlist[MAX_INDICES_PER_ATTESTATION]) -> Sequence[ValidatorIndex]:
2018-11-30 14:28:33 +00:00
"""
2019-06-28 11:23:22 +00:00
Return the sorted attesting indices corresponding to ``data`` and ``bits``.
2018-11-30 14:28:33 +00:00
"""
2019-06-22 20:49:53 +00:00
committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard)
2019-06-28 11:23:22 +00:00
return sorted([index for i, index in enumerate(committee) if bits[i]])
2018-11-20 07:40:04 +00:00
```
2019-05-07 09:33:51 +00:00
### `int_to_bytes`
2018-11-30 14:28:33 +00:00
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
2019-06-24 22:24:13 +00:00
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
2019-02-03 10:14:02 +00:00
"""
2019-05-26 15:42:37 +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
```
2019-01-28 19:15:43 +00:00
### `get_domain`
2018-12-05 14:41:11 +00:00
```python
2019-03-31 09:55:24 +00:00
def get_domain(state: BeaconState,
domain_type: int,
2019-06-11 04:15:52 +00:00
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
2019-05-21 17:30:38 +00:00
return bls_domain(domain_type, fork_version)
2018-12-05 14:41:11 +00:00
```
2019-03-26 19:40:19 +00:00
### `convert_to_indexed`
2018-12-07 01:02:23 +00:00
```python
2019-04-03 19:22:27 +00:00
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)
2019-06-13 20:01:10 +00:00
assert set(custody_bit_1_indices).issubset(attesting_indices)
2019-03-28 17:26:04 +00:00
custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices]
2018-12-07 20:09:49 +00:00
2019-03-26 19:40:19 +00:00
return IndexedAttestation(
2019-03-28 17:26:04 +00:00
custody_bit_0_indices=custody_bit_0_indices,
custody_bit_1_indices=custody_bit_1_indices,
2019-03-22 11:10:44 +00:00
data=attestation.data,
2019-04-19 03:17:29 +00:00
signature=attestation.signature,
2019-03-22 11:10:44 +00:00
)
```
2019-05-07 16:34:19 +00:00
### `validate_indexed_attestation`
2019-03-22 11:10:44 +00:00
```python
2019-05-07 16:34:19 +00:00
def validate_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> None:
2019-03-22 11:10:44 +00:00
"""
2019-05-02 08:24:24 +00:00
Verify validity of ``indexed_attestation``.
2019-03-22 11:10:44 +00:00
"""
2019-05-02 08:24:24 +00:00
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
2019-05-07 16:34:19 +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(
2018-12-23 10:48:11 +00:00
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]),
2018-12-23 10:48:11 +00:00
],
2019-02-07 21:09:41 +00:00
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)),
2018-12-23 10:48:11 +00:00
],
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-12 18:55:28 +00:00
)
2018-12-07 01:02:23 +00:00
```
2019-05-01 06:42:49 +00:00
### `is_slashable_attestation_data`
2019-04-30 18:55:14 +00:00
```python
2019-05-01 06:42:49 +00:00
def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
2019-04-30 18:55:14 +00:00
"""
2019-05-01 06:42:49 +00:00
Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules.
2019-04-30 18:55:14 +00:00
"""
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 )
2019-04-30 18:55:14 +00:00
)
```
2019-01-28 19:15:43 +00:00
### `integer_squareroot`
2018-09-30 23:02:09 +00:00
2018-09-30 14:56:43 +00:00
```python
2018-11-30 14:28:33 +00:00
def integer_squareroot(n: int) -> int:
"""
2019-01-23 04:47:07 +00:00
The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``.
2018-11-30 14:28:33 +00:00
"""
2019-01-11 00:09:58 +00:00
assert n >= 0
2018-09-30 23:38:47 +00:00
x = n
y = (x + 1) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
2018-09-30 14:56:43 +00:00
```
2019-02-20 07:45:19 +00:00
### `get_delayed_activation_exit_epoch`
2019-01-23 04:47:07 +00:00
```python
2019-02-20 07:45:19 +00:00
def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
2019-01-23 04:47:07 +00:00
"""
2019-02-20 07:45:19 +00:00
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
2019-01-23 04:47:07 +00:00
"""
2019-06-11 04:15:52 +00:00
return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY)
2019-01-23 04:47:07 +00:00
```
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-03-01 03:07:10 +00:00
)
2019-04-14 06:49:17 +00:00
```
2019-03-12 17:07:20 +00:00
2019-01-28 19:15:43 +00:00
### `bls_verify`
2019-02-09 15:21:38 +00:00
2019-06-25 13:32:56 +00:00
`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
2019-01-28 19:15:43 +00:00
### `bls_verify_multiple`
2019-03-11 16:28:39 +00:00
2019-06-25 13:32:56 +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 ).
2018-11-27 19:51:12 +00:00
2019-01-28 19:15:43 +00:00
### `bls_aggregate_pubkeys`
2018-12-14 15:39:14 +00:00
2019-06-25 13:32:56 +00:00
`bls_aggregate_pubkeys` is a function for aggregating multiple BLS public keys into a single aggregate key, as defined in the [BLS Signature spec ](../bls_signature.md#bls_aggregate_pubkeys ).
2018-12-05 18:40:08 +00:00
2018-12-28 18:04:03 +00:00
### Routines for updating validator status
2018-10-01 22:19:16 +00:00
2019-05-06 15:30:32 +00:00
*Note*: All functions in this section mutate `state` .
2018-12-10 22:42:28 +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-05-11 11:41:05 +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
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]
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):
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-04-20 05:17:33 +00:00
current_epoch = get_current_epoch(state)
2019-03-29 07:26:26 +00:00
initiate_validator_exit(state, slashed_index)
2019-06-09 19:41:21 +00:00
state.validators[slashed_index].slashed = True
2019-06-19 19:59:44 +00:00
state.validators[slashed_index].withdrawable_epoch = Epoch(current_epoch + EPOCHS_PER_SLASHED_BALANCES_VECTOR)
2019-06-09 19:41:21 +00:00
slashed_balance = state.validators[slashed_index].effective_balance
2019-06-19 19:59:44 +00:00
state.slashed_balances[current_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] += slashed_balance
2019-03-25 14:30:59 +00:00
2019-04-17 02:32:50 +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-11 04:15:52 +00:00
whistleblowing_reward = Gwei(slashed_balance // WHISTLEBLOWING_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblowing_reward // PROPOSER_REWARD_QUOTIENT)
2019-03-25 14:30:59 +00:00
increase_balance(state, proposer_index, proposer_reward)
2019-03-25 14:49:35 +00:00
increase_balance(state, whistleblower_index, whistleblowing_reward - proposer_reward)
2019-03-25 14:54:43 +00:00
decrease_balance(state, slashed_index, whistleblowing_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-08 18:00:50 +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
2019-06-08 18:00:50 +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
2019-06-25 13:32:56 +00:00
When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let:
2019-05-05 16:15:05 +00:00
2019-06-08 18:00:50 +00:00
* `genesis_deposits = deposits`
2019-06-10 12:41:28 +00:00
* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400`
2019-06-08 18:00:50 +00:00
* `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`
2019-06-08 18:00:50 +00:00
* `genesis_eth1_data.deposit_count = len(genesis_deposits)`
2019-03-03 11:04:28 +00:00
2019-06-25 13:32:56 +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
2019-06-08 18:00:50 +00:00
```python
2019-06-22 16:12:42 +00:00
def is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool:
2019-06-08 18:00:50 +00:00
# Process deposits
state = BeaconState()
for deposit in deposits:
process_deposit(state, deposit)
# Count active validators at genesis
active_validator_count = 0
2019-06-25 16:24:14 +00:00
for validator in state.validators:
2019-06-09 10:03:38 +00:00
if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
2019-06-08 18:00:50 +00:00
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-06-08 18:00:50 +00:00
```
2019-05-05 16:15:05 +00:00
### Genesis state
2019-06-08 18:00:50 +00:00
Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_data)` .
2018-11-16 16:41:59 +00:00
2018-10-02 15:20:07 +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:
2019-05-20 09:16:20 +00:00
state = BeaconState(
genesis_time=genesis_time,
2019-06-20 18:15:48 +00:00
eth1_data=eth1_data,
2019-05-20 09:16:20 +00:00
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:
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
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
)
2019-06-19 19:59:44 +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
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
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
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-02-11 21:30:36 +00:00
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:
2019-05-28 14:05:25 +00:00
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)
2019-06-11 04:15:52 +00:00
state.slot += 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-03-08 16:48:46 +00:00
2019-05-03 20:21:42 +00:00
# Cache latest block header state root
2019-03-08 16:48:46 +00:00
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-03-08 16:48:46 +00:00
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
2018-12-10 10:11:41 +00:00
2019-06-25 13:32:56 +00:00
*Note*: The `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
2019-06-05 19:42:55 +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_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
```
2018-12-10 10:11:41 +00:00
2019-03-07 19:05:34 +00:00
#### Helper functions
2019-03-03 11:04:28 +00:00
```python
2019-04-22 06:13:46 +00:00
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
```
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 [
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
]
```
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-11 04:15:52 +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-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
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:
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-03-07 19:05:34 +00:00
```python
2019-05-09 05:54:38 +00:00
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
```
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:
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
2019-06-28 11:35:50 +00:00
state.justification_bits = [0b0] + state.justification_bits[:JUSTIFICATION_BITS_LENGTH - 1] # Bitshift
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(previous_epoch, 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(current_epoch, 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-03-07 19:05:34 +00:00
#### Crosslinks
2018-11-16 12:54:03 +00:00
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]
2019-04-29 16:02:39 +00:00
for epoch in (get_previous_epoch(state), get_current_epoch(state)):
for offset in range(get_epoch_committee_count(state, epoch)):
2019-06-11 04:15:52 +00:00
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
2019-06-24 22:24:13 +00:00
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
2019-05-01 21:51:43 +00:00
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
2019-03-01 13:59:52 +00:00
```
2018-12-05 11:22:15 +00:00
2019-01-28 19:15:43 +00:00
#### Rewards and penalties
2018-12-12 15:07:44 +00:00
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
```
2019-04-17 02:32:50 +00:00
```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)
2019-04-22 06:13:46 +00:00
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-03-21 20:11:05 +00:00
]
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
2019-04-17 04:06:28 +00:00
else:
2019-04-24 04:23:51 +00:00
penalties[index] += get_base_reward(state, index)
# Proposer and inclusion delay micro-rewards
2019-04-24 05:32:43 +00:00
for index in get_unslashed_attesting_indices(state, matching_source_attestations):
2019-06-11 04:15:52 +00:00
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)
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
2019-06-21 22:33:43 +00:00
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:
2019-06-11 04:15:52 +00:00
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:
2019-06-11 04:15:52 +00:00
penalties[index] += Gwei(
2019-06-09 19:41:21 +00:00
state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
2019-05-09 05:54:38 +00:00
)
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
2019-03-01 13:59:52 +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))]
2019-04-29 16:02:39 +00:00
epoch = get_previous_epoch(state)
for offset in range(get_epoch_committee_count(state, epoch)):
2019-06-11 04:15:52 +00:00
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
2019-06-24 22:24:13 +00:00
crosslink_committee = set(get_crosslink_committee(state, epoch, shard))
2019-05-01 21:51:43 +00:00
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard)
2019-04-29 16:02:39 +00:00
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
2019-04-25 07:37:05 +00:00
return rewards, penalties
2019-03-01 13:59:52 +00:00
```
2018-10-01 22:19:16 +00:00
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:
2019-04-11 12:28:42 +00:00
if get_current_epoch(state) == GENESIS_EPOCH:
return
2019-04-20 05:17:33 +00:00
rewards1, penalties1 = get_attestation_deltas(state)
2019-03-21 21:29:14 +00:00
rewards2, penalties2 = get_crosslink_deltas(state)
2019-06-17 21:51:00 +00:00
for index in range(len(state.validators)):
2019-06-11 04:15:52 +00:00
increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[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-05-09 05:54:38 +00:00
if (
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
validator.effective_balance >= MAX_EFFECTIVE_BALANCE
):
2019-04-14 12:55:38 +00:00
validator.activation_eligibility_epoch = get_current_epoch(state)
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-04-22 05:16:34 +00:00
# Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
2019-04-06 14:24:50 +00:00
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
2019-06-21 22:33:43 +00:00
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)
2019-04-22 05:12:30 +00:00
# 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]
2019-04-22 10:49:07 +00:00
if validator.activation_epoch == FAR_FUTURE_EPOCH:
2019-04-22 05:12:30 +00:00
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)
2019-05-26 15:42:37 +00:00
total_balance = get_total_active_balance(state)
2019-03-07 19:05:34 +00:00
2019-05-26 15:42:37 +00:00
# Compute slashed balances in the current epoch
2019-06-22 05:34:02 +00:00
total_at_start = state.slashed_balances[(epoch + 1) % EPOCHS_PER_SLASHED_BALANCES_VECTOR]
total_at_end = state.slashed_balances[epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR]
2019-03-07 19:05:34 +00:00
total_penalties = total_at_end - total_at_start
2019-06-09 19:41:21 +00:00
for index, validator in enumerate(state.validators):
2019-06-22 05:34:02 +00:00
if validator.slashed and epoch + EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2 == validator.withdrawable_epoch:
2019-03-07 19:05:34 +00:00
penalty = max(
2019-04-22 06:13:46 +00:00
validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance,
2019-04-22 06:34:50 +00:00
validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT
2019-03-07 19:05:34 +00:00
)
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)
next_epoch = current_epoch + 1
2019-04-17 04:30:03 +00:00
# Reset eth1 data votes
2019-04-24 19:15:06 +00:00
if (state.slot + 1) % SLOTS_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]
2019-04-22 06:13:46 +00:00
HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
if balance < validator.effective_balance or validator . effective_balance + 3 * HALF_INCREMENT < balance:
2019-04-26 14:46:35 +00:00
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
2019-04-18 09:08:34 +00:00
# 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
2019-06-19 19:59:44 +00:00
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](
2019-06-22 16:34:33 +00:00
get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY))
)
2019-03-07 19:05:34 +00:00
)
# Set total slashed balances
2019-06-19 19:59:44 +00:00
state.slashed_balances[next_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] = (
state.slashed_balances[current_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR]
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-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,
2019-06-22 15:38:30 +00:00
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
2019-04-19 03:17:29 +00:00
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:
2019-06-19 19:59:44 +00:00
epoch = get_current_epoch(state)
# Verify RANDAO reveal
2019-06-09 19:41:21 +00:00
proposer = state.validators[get_beacon_proposer_index(state)]
2019-06-19 19:59:44 +00:00
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
```
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-05-03 20:21:42 +00:00
# Verify that there are no duplicate transfers
2019-05-01 11:04:27 +00:00
assert len(body.transfers) == len(set(body.transfers))
2019-06-18 00:54:08 +00:00
2019-06-20 18:15:48 +00:00
all_operations = (
2019-06-20 18:05:34 +00:00
(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]]
2019-06-20 18:15:48 +00:00
for operations, function in all_operations:
2019-05-01 11:04:27 +00:00
for operation in operations:
function(state, operation)
```
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:
2019-03-07 19:05:34 +00:00
"""
2019-03-31 05:02:10 +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]
2019-03-12 15:49:04 +00:00
# Verify that the epoch is the same
2019-03-12 12:24:37 +00:00
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))
2019-04-19 03:17:29 +00:00
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
"""
2019-03-31 05:02:10 +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)
2019-05-07 16:34:19 +00:00
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
2019-05-27 07:17:20 +00:00
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-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-01-30 09:25:39 +00:00
"""
2019-03-31 05:02:10 +00:00
Process ``Attestation`` operation.
2019-01-30 09:25:39 +00:00
"""
2019-05-05 18:30:55 +00:00
data = attestation.data
2019-06-13 13:46:22 +00:00
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-06-13 13:46:22 +00:00
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-15 12:40:52 +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-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)
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-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)
2019-05-19 13:33:01 +00:00
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
2019-05-08 14:42:47 +00:00
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
2019-04-12 08:57:55 +00:00
```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.
2019-04-12 08:57:55 +00:00
"""
# Verify the Merkle branch
2019-04-20 06:32:41 +00:00
assert verify_merkle_branch(
2019-04-14 21:54:08 +00:00
leaf=hash_tree_root(deposit.data),
2019-04-12 08:57:55 +00:00
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-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-05-21 22:07:52 +00:00
# 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.
2019-06-25 13:32:56 +00:00
# Note: Deposits are valid across forks, hence the deposit domain is retrieved directly from `bls_domain`
2019-05-21 17:30:38 +00:00
if not bls_verify(
2019-05-21 23:35:24 +00:00
pubkey, signing_root(deposit.data), deposit.data.signature, bls_domain(DOMAIN_DEPOSIT)
2019-05-21 17:30:38 +00:00
):
2019-04-12 08:57:55 +00:00
return
2019-04-22 06:13:46 +00:00
# Add validator and balance entries
2019-06-09 19:41:21 +00:00
state.validators.append(Validator(
2019-04-12 08:57:55 +00:00
pubkey=pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
2019-04-13 22:30:13 +00:00
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
2019-04-12 08:57:55 +00:00
activation_epoch=FAR_FUTURE_EPOCH,
exit_epoch=FAR_FUTURE_EPOCH,
withdrawable_epoch=FAR_FUTURE_EPOCH,
2019-04-26 14:46:35 +00:00
effective_balance=min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
2019-04-22 06:13:46 +00:00
))
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-03-10 12:50:28 +00:00
def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
2019-02-12 12:24:19 +00:00
"""
2019-03-31 05:02:10 +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
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
assert get_current_epoch(state) >= exit.epoch
2019-03-19 20:43:05 +00:00
# Verify the validator has been active long enough
2019-05-04 03:51:59 +00:00
assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
2019-03-07 19:05:34 +00:00
# Verify signature
2019-03-31 09:55:24 +00:00
domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
2019-04-19 03:17:29 +00:00
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)
2018-10-01 22:19:16 +00:00
```
2018-11-07 16:47:27 +00:00
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:
"""
2019-03-31 05:02:10 +00:00
Process ``Transfer`` operation.
2019-03-07 19:05:34 +00:00
"""
2019-06-26 19:21:17 +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
2019-06-24 22:40:37 +00:00
# Sender must satisfy at least one of the following conditions in the parenthesis:
2019-03-07 19:05:34 +00:00
assert (
2019-06-24 22:40:37 +00:00
# * Has not been activated
2019-06-09 19:41:21 +00:00
state.validators[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
2019-06-24 22:40:37 +00:00
# * Is withdrawable
2019-06-09 19:41:21 +00:00
get_current_epoch(state) >= state.validators[transfer.sender].withdrawable_epoch or
2019-06-24 22:40:37 +00:00
# * 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
2019-04-19 03:17:29 +00:00
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
2019-03-11 16:44:18 +00:00
decrease_balance(state, transfer.sender, transfer.amount + transfer.fee)
increase_balance(state, transfer.recipient, transfer.amount)
2019-04-17 02:32:50 +00:00
increase_balance(state, get_beacon_proposer_index(state), transfer.fee)
2019-04-14 11:53:32 +00:00
# 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
```