diff --git a/docs/specs/beacon-chain.md b/docs/specs/beacon-chain.md index fb903535f..0aedeb8dd 100644 --- a/docs/specs/beacon-chain.md +++ b/docs/specs/beacon-chain.md @@ -143,7 +143,7 @@ This document represents the specification for Phase 0 -- The Beacon Chain. -At the core of Ethereum proof-of-stake is a system chain called the "beacon chain". The beacon chain stores and manages the registry of validators. In the initial deployment phases of proof-of-stake, the only mechanism to become a validator is to make a one-way ETH transaction to a deposit contract on the Ethereum proof-of-work chain. Activation as a validator happens when 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. +At the core of Ethereum proof-of-stake is a system chain called the "beacon chain". The beacon chain stores and manages the registry of validators. In the initial deployment phases of proof-of-stake, the only mechanism to become a validator is to make a one-way ETH transaction to a deposit contract on the Ethereum execution chain. Activation as a validator happens when deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block (in a later upgrade) and proof-of-stake votes for a beacon block (Phase 0). ## Notation @@ -253,7 +253,7 @@ The following values are (non-configurable) constants used throughout the specif *Note*: The below configuration is bundled as a preset: a bundle of configuration variables which are expected to differ between different modes of operation, e.g. testing, but not generally between different networks. -Additional preset configurations can be found in the [`configs`](../../configs) directory. +Additional preset configurations can be found in the `configs` directory. ### Misc @@ -416,7 +416,7 @@ Testnets and other types of chain instances may use a different configuration. ## Containers -The following types are [SimpleSerialize (SSZ)](../../ssz/simple-serialize.md) containers. +The following types are SimpleSerialize (SSZ) containers. *Note*: The definitions are ordered topologically to facilitate execution of the spec. @@ -993,7 +993,7 @@ def saturating_sub(a: int, b: int) -> int: #### `hash_tree_root` -`def hash_tree_root(object: SSZSerializable) -> Root` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the [SSZ spec](../../ssz/simple-serialize.md#merkleization). +`def hash_tree_root(object: SSZSerializable) -> Root` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the SSZ spec. #### BLS signatures @@ -1860,13 +1860,13 @@ Modified in altair to use `MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX` instead of ` ## Genesis -Before the Ethereum beacon chain genesis has been triggered, and for every Ethereum proof-of-work block, let `candidate_state = initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` where: +Before the Ethereum beacon chain genesis has been triggered, and for every Ethereum execution block, let `candidate_state = initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` where: -- `eth1_block_hash` is the hash of the Ethereum proof-of-work block +- `eth1_block_hash` is the hash of the Ethereum execution block - `eth1_timestamp` is the Unix timestamp corresponding to `eth1_block_hash` - `deposits` is the sequence of all deposits, ordered chronologically, up to (and including) the block with hash `eth1_block_hash` -Proof-of-work blocks must only be considered once they are at least `SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE` seconds old (i.e. `eth1_timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time`). Due to this constraint, if `GENESIS_DELAY < SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE`, then the `genesis_time` can happen before the time/state is first known. Values should be configured to avoid this case. +execution blocks must only be considered once they are at least `SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE` seconds old (i.e. `eth1_timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time`). Due to this constraint, if `GENESIS_DELAY < SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE`, then the `genesis_time` can happen before the time/state is first known. Values should be configured to avoid this case. ```python def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, diff --git a/docs/specs/deposit-contract.md b/docs/specs/deposit-contract.md new file mode 100644 index 000000000..eb8034532 --- /dev/null +++ b/docs/specs/deposit-contract.md @@ -0,0 +1,72 @@ +# Phase 0 -- Deposit Contract + +## Table of contents + + + + +- [Introduction](#introduction) +- [Constants](#constants) +- [Configuration](#configuration) +- [Staking deposit contract](#staking-deposit-contract) + - [`deposit` function](#deposit-function) + - [Deposit amount](#deposit-amount) + - [Withdrawal credentials](#withdrawal-credentials) + - [`DepositEvent` log](#depositevent-log) +- [Solidity code](#solidity-code) + + + + +## Introduction + +This document represents the specification for the beacon chain deposit contract, part of Phase 0. + +## Constants + +The following values are (non-configurable) constants used throughout the specification. + +| Name | Value | +| - | - | +| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | + +## Configuration + +*Note*: The default mainnet configuration values are included here for spec-design purposes. +The different configurations for mainnet, testnets, and YAML-based testing can be found in the `configs/constant_presets` directory. +These configurations are updated for releases and may be out of sync during `dev` changes. + +| Name | Value | +| - | - | +| `DEPOSIT_CHAIN_ID` | `1` | +| `DEPOSIT_NETWORK_ID` | `1` | +| `DEPOSIT_CONTRACT_ADDRESS` | `0x00000000219ab540356cBB839Cbe05303d7705Fa` | + +## Staking deposit contract + +The initial deployment phases of Ethereum proof-of-stake are implemented without consensus changes to the existing Ethereum execution chain. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to the Ethereum execution chain defined by the [chain-id](https://eips.ethereum.org/EIPS/eip-155) -- `DEPOSIT_CHAIN_ID` -- and the network-id -- `DEPOSIT_NETWORK_ID` -- for deposits of ETH to the beacon chain. + +_Note_: See [here](https://chainid.network/) for a comprehensive list of public Ethereum chain chain-id's and network-id's. + +### `deposit` function + +The deposit contract has a public `deposit` function to make deposits. It takes as arguments `bytes calldata pubkey, bytes calldata withdrawal_credentials, bytes calldata signature, bytes32 deposit_data_root`. The first three arguments populate a [`DepositData`](./beacon-chain.md#depositdata) object, and `deposit_data_root` is the expected `DepositData` root as a protection against malformatted calldata. + +#### Deposit amount + +The amount of ETH (rounded down to the closest Gwei) sent to the deposit contract is the deposit amount, which must be of size at least `MIN_DEPOSIT_AMOUNT` Gwei. + +#### Withdrawal credentials + +One of the `DepositData` fields is `withdrawal_credentials` which constrains validator withdrawals. +The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. +The withdrawal prefixes currently supported are `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. +Read more in the [validator guide](./validator.md#withdrawal-credentials). + +*Note*: The deposit contract does not validate the `withdrawal_credentials` field. +Support for new withdrawal prefixes can be added without modifying the deposit contract. + +#### `DepositEvent` log + +Every deposit emits a `DepositEvent` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract. + diff --git a/docs/specs/fork-choice.md b/docs/specs/fork-choice.md index 537464aa5..7a168981e 100644 --- a/docs/specs/fork-choice.md +++ b/docs/specs/fork-choice.md @@ -80,7 +80,7 @@ Any of the above handlers that trigger an unhandled exception (e.g. a failed ass 1) **Leap seconds**: Slots will last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds around leap seconds. This is automatically handled by [UNIX time](https://en.wikipedia.org/wiki/Unix_time). 2) **Honest clocks**: Honest nodes are assumed to have clocks synchronized within `SECONDS_PER_SLOT` seconds of each other. -3) **Eth1 data**: The large `ETH1_FOLLOW_DISTANCE` specified in the [honest validator document](./validator.md) should ensure that `state.latest_eth1_data` of the canonical beacon chain remains consistent with the canonical Ethereum proof-of-work chain. If not, emergency manual intervention will be required. +3) **Eth1 data**: The large `ETH1_FOLLOW_DISTANCE` specified in the [honest validator document](./validator.md) should ensure that `state.latest_eth1_data` of the canonical beacon chain remains consistent with the canonical Ethereum execution chain. If not, emergency manual intervention will be required. 4) **Manual forks**: Manual forks may arbitrarily change the fork choice rule but are expected to be enacted at epoch transitions, with the fork details reflected in `state.fork`. 5) **Implementation**: The implementation found in this specification is constructed for ease of understanding rather than for optimization in computation, space, or any other resource. A number of optimized alternatives can be found [here](https://github.com/protolambda/lmd-ghost). @@ -892,7 +892,7 @@ As per EIP-3675, before a post-transition block is finalized, `notify_forkchoice ##### `safe_block_hash` The `safe_block_hash` parameter MUST be set to return value of -[`get_safe_execution_payload_hash(store: Store)`](../../fork_choice/safe-block.md#get_safe_execution_payload_hash) function. +`get_safe_execution_payload_hash(store: Store)` function. ##### `should_override_forkchoice_update` diff --git a/docs/specs/p2p-interface.md b/docs/specs/p2p-interface.md index 4d28e36f6..5491ed8e1 100644 --- a/docs/specs/p2p-interface.md +++ b/docs/specs/p2p-interface.md @@ -840,7 +840,7 @@ Clients MUST treat as valid any byte sequences. The token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Only one value is possible at this time: -- `ssz_snappy`: The contents are first [SSZ-encoded](../../ssz/simple-serialize.md) +- `ssz_snappy`: The contents are first SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy) frames compression. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the `BeaconBlocksByRoot` request is an SSZ-encoded list of `Root`'s. @@ -848,7 +848,7 @@ Only one value is possible at this time: ##### SSZ-snappy encoding strategy -The [SimpleSerialize (SSZ) specification](../../ssz/simple-serialize.md) outlines how objects are SSZ-encoded. +The SimpleSerialize (SSZ) specification outlines how objects are SSZ-encoded. To achieve snappy encoding on top of SSZ, we feed the serialized form of the object to the Snappy compressor on encoding. The inverse happens on decoding. diff --git a/docs/specs/validator.md b/docs/specs/validator.md index 670919bd1..32dc1ead7 100644 --- a/docs/specs/validator.md +++ b/docs/specs/validator.md @@ -73,7 +73,7 @@ This is an accompanying document to [The Beacon Chain](./beacon-chain.md), which ## Introduction -This document represents the expected behavior of an "honest validator" with respect to Phase 0 of the Ethereum proof-of-stake protocol. This document does not distinguish between a "node" (i.e. the functionality of following and reading the beacon chain) and a "validator client" (i.e. the functionality of actively participating in consensus). The separation of concerns between these (potentially) two pieces of software is left as a design decision that is out of scope. +This document represents the expected behavior of an "honest validator" of the Ethereum proof-of-stake protocol. This document does not distinguish between a "node" (i.e. the functionality of following and reading the beacon chain) and a "validator client" (i.e. the functionality of actively participating in consensus). The separation of concerns between these (potentially) two pieces of software is left as a design decision that is out of scope. A validator is an entity that participates in the consensus of the Ethereum proof-of-stake protocol. This is an optional role for users in which they can post ETH as collateral and verify and attest to the validity of blocks to seek financial returns in exchange for building and securing the protocol. This is similar to proof-of-work networks in which miners provide collateral in the form of hardware/hash-power to seek returns in exchange for building and securing the protocol. @@ -84,7 +84,7 @@ Block proposers incorporate the (aggregated) sync committee signatures into each ## Prerequisites -All terminology, constants, functions, and protocol mechanics defined in the [The Beacon Chain](./beacon-chain.md) and [Deposit Contract](./deposit-contract.md) doc are requisite for this document and used throughout. Please see the Phase 0 doc before continuing and use as a reference throughout. +All terminology, constants, functions, and protocol mechanics defined in the [The Beacon Chain](./beacon-chain.md) and [Deposit Contract](./deposit-contract.md) doc are requisite for this document and used throughout. ## Constants @@ -308,7 +308,7 @@ withdrawals to `eth1_withdrawal_address` will simply be increases to the account ### Submit deposit -In Phase 0, all incoming validator deposits originate from the Ethereum proof-of-work chain defined by `DEPOSIT_CHAIN_ID` and `DEPOSIT_NETWORK_ID`. Deposits are made to the [deposit contract](./deposit-contract.md) located at `DEPOSIT_CONTRACT_ADDRESS`. +Deposits are made to the [deposit contract](./deposit-contract.md) located at `DEPOSIT_CONTRACT_ADDRESS`. To submit a deposit: @@ -320,13 +320,13 @@ To submit a deposit: - Let `deposit_message` be a `DepositMessage` with all the `DepositData` contents except the `signature`. - Let `signature` be the result of `bls.Sign` of the `compute_signing_root(deposit_message, domain)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (*Warning*: Deposits *must* be signed with `GENESIS_FORK_VERSION`, calling `compute_domain` without a second argument defaults to the correct version). - Let `deposit_data_root` be `hash_tree_root(deposit_data)`. -- Send a transaction on the Ethereum proof-of-work chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96], deposit_data_root: bytes32)` along with a deposit of `amount` Gwei. +- Send a transaction on the Ethereum execution chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96], deposit_data_root: bytes32)` along with a deposit of `amount` Gwei. *Note*: Deposits made for the same `pubkey` are treated as for the same validator. A singular `Validator` will be added to `state.validators` with each additional deposit amount added to the validator's balance. A validator can only be activated when total deposits for the validator pubkey meet or exceed `MAX_EFFECTIVE_BALANCE`. ### Process deposit -Deposits cannot be processed into the beacon chain until the proof-of-work block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes *a minimum* of `ETH1_FOLLOW_DISTANCE` Eth1 blocks (~8 hours) plus `EPOCHS_PER_ETH1_VOTING_PERIOD` epochs (~6.8 hours). Once the requisite proof-of-work block data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validators` within an epoch or two. The validator is then in a queue to be activated. +Deposits cannot be processed into the beacon chain until the execution block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes *a minimum* of `ETH1_FOLLOW_DISTANCE` Eth1 blocks (~8 hours) plus `EPOCHS_PER_ETH1_VOTING_PERIOD` epochs (~6.8 hours). Once the requisite execution block data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validators` within an epoch or two. The validator is then in a queue to be activated. ### Validator index @@ -605,7 +605,7 @@ Up to `MAX_ATTESTATIONS`, aggregate attestations can be included in the `block`. If there are any unprocessed deposits for the existing `state.eth1_data` (i.e. `state.eth1_data.deposit_count > state.eth1_deposit_index`), then pending deposits *must* be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, eth1_data.deposit_count - state.eth1_deposit_index)`. These [`deposits`](./beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [deposit contract](./deposit-contract.md) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](./beacon-chain.md#deposits). -The `proof` for each deposit must be constructed against the deposit root contained in `state.eth1_data` rather than the deposit root at the time the deposit was initially logged from the proof-of-work chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation. +The `proof` for each deposit must be constructed against the deposit root contained in `state.eth1_data` rather than the deposit root at the time the deposit was initially logged from the execution chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation. ##### Voluntary exits @@ -1151,7 +1151,7 @@ def get_contribution_and_proof_signature(state: BeaconState, ## How to avoid slashing -"Slashing" is the burning of some amount of validator funds and immediate ejection from the active validator set. In Phase 0, there are two ways in which funds can be slashed: [proposer slashing](#proposer-slashing) and [attester slashing](#attester-slashing). Although being slashed has serious repercussions, it is simple enough to avoid being slashed all together by remaining *consistent* with respect to the messages a validator has previously signed. +"Slashing" is the burning of some amount of validator funds and immediate ejection from the active validator set. There are two ways in which funds can be slashed: [proposer slashing](#proposer-slashing) and [attester slashing](#attester-slashing). Although being slashed has serious repercussions, it is simple enough to avoid being slashed all together by remaining *consistent* with respect to the messages a validator has previously signed. *Note*: Signed data must be within a sequential `Fork` context to conflict. Messages cannot be slashed across diverging forks. If the previous fork version is 1 and the chain splits into fork 2 and 102, messages from 1 can be slashable against messages in forks 1, 2, and 102. Messages in 2 cannot be slashable against messages in 102, and vice versa. diff --git a/native/ssz_nif/README.md b/native/ssz_nif/README.md index 647151776..f2c4cb263 100644 --- a/native/ssz_nif/README.md +++ b/native/ssz_nif/README.md @@ -27,4 +27,4 @@ After implementing everything, check that spec-tests pass by running `make spec- ## Containers with constants -Some SSZ containers depend on variable configuration, for example `HistoricalBatch`. In these cases, we should implement the functionality for the "minimal" and "mainnet" presets, and map the test handlers with their corresponding structs inside the config modules from [`test/spec/configs`](../../test/spec/configs). +Some SSZ containers depend on variable configuration, for example `HistoricalBatch`. In these cases, we should implement the functionality for the "minimal" and "mainnet" presets, and map the test handlers with their corresponding structs inside the config modules from `test/spec/configs`.