Merge branch 'master' into JustinDrake-patch-8
This commit is contained in:
commit
0afafe1c76
|
@ -2,19 +2,19 @@
|
|||
|
||||
**Warning: This document is pending academic review and should not yet be considered secure.**
|
||||
|
||||
See https://z.cash/blog/new-snark-curve/ for BLS-12-381 parameters.
|
||||
See https://z.cash/blog/new-snark-curve/ for BLS-12-381 parameters. `q` is the field modulus.
|
||||
|
||||
We represent coordinates as defined in https://github.com/zkcrypto/pairing/tree/master/src/bls12_381/.
|
||||
|
||||
Specifically, a point in G1 as a 384-bit integer `z`, which we decompose into:
|
||||
|
||||
* `x = z % 2**381`
|
||||
* `x = z % 2**381` (must be `< q`)
|
||||
* `highflag = z // 2**382`
|
||||
* `lowflag = (z % 2**382) // 2**381`
|
||||
|
||||
If `highflag == 3`, the point is the point at infinity and we require `lowflag = x = 0`. Otherwise, we require `highflag == 2`, in which case the point is `(x, y)` where `y` is the valid coordinate such that `(y * 2) // q == lowflag`.
|
||||
|
||||
We represent a point in G2 as a pair of 384-bit integers `(z1, z2)` that are each decomposed into `x1`, `highflag1`, `lowflag1`, `x2`, `highflag2`, `lowflag2` as above. We require `lowflag2 == highflag2 == 0`. If `highflag1 == 3`, the point is the point at infinity and we require `lowflag1 == x1 == x2 == 0`. Otherwise, we require `highflag == 2`, in which case the point is `(x1 * i + x2, y)` where `y` is the valid coordinate such that the imaginary part of `y` satisfies `(y_im * 2) // q == lowflag1`.
|
||||
We represent a point in G2 as a pair of 384-bit integers `(z1, z2)` that are each decomposed into `x1`, `highflag1`, `lowflag1`, `x2`, `highflag2`, `lowflag2` as above, where `x1` and `x2` must both be `< q`. We require `lowflag2 == highflag2 == 0`. If `highflag1 == 3`, the point is the point at infinity and we require `lowflag1 == x1 == x2 == 0`. Otherwise, we require `highflag == 2`, in which case the point is `(x1 * i + x2, y)` where `y` is the valid coordinate such that the imaginary part of `y` satisfies `(y_im * 2) // q == lowflag1`.
|
||||
|
||||
`BLSVerify(pubkey: uint384, msg: bytes32, sig: [uint384], domain: uint64)` is done as follows:
|
||||
|
||||
|
|
|
@ -17,20 +17,28 @@
|
|||
- [Time parameters](#time-parameters)
|
||||
- [Reward and penalty quotients](#reward-and-penalty-quotients)
|
||||
- [Status codes](#status-codes)
|
||||
- [Special record types](#special-record-types)
|
||||
- [Max operations per block](#max-operations-per-block)
|
||||
- [Validator registry delta flags](#validator-registry-delta-flags)
|
||||
- [Signature domains](#signature-domains)
|
||||
- [Data structures](#data-structures)
|
||||
- [Deposits](#deposits)
|
||||
- [`DepositParametersRecord`](#depositparametersrecord)
|
||||
- [Beacon chain operations](#beacon-chain-operations)
|
||||
- [Proposer slashings](#proposer-slashings)
|
||||
- [`ProposerSlashing`](#proposerslashing)
|
||||
- [Casper slashings](#casper-slashings)
|
||||
- [`CasperSlashing`](#casperslashing)
|
||||
- [`SlashableVoteData`](#slashablevotedata)
|
||||
- [Attestations](#attestations)
|
||||
- [`Attestation`](#attestation)
|
||||
- [`AttestationData`](#attestationdata)
|
||||
- [Deposits](#deposits)
|
||||
- [`Deposit`](#deposit)
|
||||
- [`DepositParameters`](#depositparameters)
|
||||
- [Exits](#exits)
|
||||
- [`Exit`](#exit)
|
||||
- [Beacon chain blocks](#beacon-chain-blocks)
|
||||
- [`BeaconBlockHeader`](#beaconblockheader)
|
||||
- [`BeaconBlockBody`](#beaconblockbody)
|
||||
- [`BeaconBlock`](#beaconblock)
|
||||
- [`AttestationRecord`](#attestationrecord)
|
||||
- [`AttestationData`](#attestationdata)
|
||||
- [`BeaconBlockBody`](#beaconblockbody)
|
||||
- [`ProposalSignedData`](#proposalsigneddata)
|
||||
- [`SpecialRecord`](#specialrecord)
|
||||
- [Beacon chain state](#beacon-chain-state)
|
||||
- [`BeaconState`](#beaconstate)
|
||||
- [`ValidatorRecord`](#validatorrecord)
|
||||
|
@ -40,12 +48,6 @@
|
|||
- [`CandidatePoWReceiptRootRecord`](#candidatepowreceiptrootrecord)
|
||||
- [`PendingAttestationRecord`](#pendingattestationrecord)
|
||||
- [`ForkData`](#forkdata)
|
||||
- [Specials](#specials)
|
||||
- [`VoluntaryExitSpecial`](#voluntaryexitspecial)
|
||||
- [`CasperSlashingSpecial`](#casperslashingspecial)
|
||||
- [`SpecialAttestationData`](#specialattestationdata)
|
||||
- [`ProposerSlashingSpecial`](#proposerslashingspecial)
|
||||
- [`DepositProofSpecial`](#depositproofspecial)
|
||||
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
|
||||
- [Deposit arguments](#deposit-arguments)
|
||||
- [`Deposit` logs](#deposit-logs)
|
||||
|
@ -64,25 +66,27 @@
|
|||
- [`get_shard_committees_at_slot`](#get_shard_committees_at_slot)
|
||||
- [`get_block_hash`](#get_block_hash)
|
||||
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
|
||||
- [`get_updated_ancestor_hashes`](#get_updated_ancestor_hashes)
|
||||
- [`get_attestation_participants`](#get_attestation_participants)
|
||||
- [`bytes1`, `bytes2`, ...](#bytes1-bytes2-)
|
||||
- [`get_effective_balance`](#get_effective_balance)
|
||||
- [`get_new_validator_registry_delta_chain_tip`](#get_new_validator_registry_delta_chain_tip)
|
||||
- [`get_domain`](#get_domain)
|
||||
- [`verify_casper_votes`](#verify_casper_votes)
|
||||
- [`integer_squareroot`](#integer_squareroot)
|
||||
- [On startup](#on-startup)
|
||||
- [Routine for activating a validator](#routine-for-activating-a-validator)
|
||||
- [Routine for exiting a validator](#routine-for-exiting-a-validator)
|
||||
- [Per-slot processing](#per-slot-processing)
|
||||
- [Proposer signature](#proposer-signature)
|
||||
- [Attestations](#attestations)
|
||||
- [RANDAO](#randao)
|
||||
- [PoW receipt root](#pow-receipt-root)
|
||||
- [Special objects](#special-objects)
|
||||
- [`VOLUNTARY_EXIT`](#voluntary_exit)
|
||||
- [`CASPER_SLASHING`](#casper_slashing)
|
||||
- [`PROPOSER_SLASHING`](#proposer_slashing)
|
||||
- [`DEPOSIT_PROOF`](#deposit_proof)
|
||||
- [Block operations](#block-operations)
|
||||
- [Proposer slashings](#proposer-slashings-1)
|
||||
- [Casper slashings](#casper-slashings-1)
|
||||
- [Attestations](#attestations-1)
|
||||
- [Deposits](#deposits-1)
|
||||
- [Exits](#exits-1)
|
||||
- [Ejections](#ejections)
|
||||
- [Per-epoch processing](#per-epoch-processing)
|
||||
- [Helpers](#helpers)
|
||||
|
@ -141,12 +145,12 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
| - | - | :-: |
|
||||
| `SHARD_COUNT` | `2**10` (= 1,024) | shards |
|
||||
| `TARGET_COMMITTEE_SIZE` | `2**8` (= 256) | [validators](#dfn-validator) |
|
||||
| `MAX_ATTESTATIONS_PER_BLOCK` | `2**7` (= 128) | attestations |
|
||||
| `EJECTION_BALANCE` | `2**4` (= 16) | ETH |
|
||||
| `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | - |
|
||||
| `GWEI_PER_ETH` | `10**9` | Gwei/ETH |
|
||||
| `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - |
|
||||
| `BLS_WITHDRAWAL_CREDENTIALS` | `0x00` | - |
|
||||
| `BLS_WITHDRAWAL_PREFIX_BYTE` | `0x00` | - |
|
||||
| `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes |
|
||||
|
||||
* For the safety of crosslinks a minimum committee size of 111 is [recommended](https://vitalik.ca/files/Ithaca201807_Sharding.pdf). (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) The shuffling algorithm generally ensures (assuming sufficient validators) committee sizes at least `TARGET_COMMITTEE_SIZE // 2`.
|
||||
|
||||
|
@ -187,10 +191,10 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
| `BASE_REWARD_QUOTIENT` | `2**11` (= 2,048) |
|
||||
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `2**9` (= 512) |
|
||||
| `INCLUDER_REWARD_QUOTIENT` | `2**3` (= 8) |
|
||||
| `INACTIVITY_PENALTY_QUOTIENT` | `2**34` (= 131,072) |
|
||||
| `INACTIVITY_PENALTY_QUOTIENT` | `2**34` (= 17,179,869,184) |
|
||||
|
||||
* The `BASE_REWARD_QUOTIENT` constant dictates the per-epoch reward. It corresponds to ~2.54% annual interest assuming 10 million participating ETH in every epoch.
|
||||
* The `INACTIVITY_PENALTY_QUOTIENT` equals `SQRT_E_DROP_TIME**2` where `SQRT_E_DROP_TIME := 2**17 slots` (~9 days) is the amount of time it takes for the inactivity penalty to cut deposits of non-participating [validators](#dfn-validator) by ~39.4%. The portion lost by offline [validators](#dfn-validator) after `D` epochs is about `D*D/2/INACTIVITY_PENALTY_QUOTIENT`.
|
||||
* The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It corresponds to ~2.54% annual interest assuming 10 million participating ETH in every epoch.
|
||||
* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**17 slots` (~9 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` slots is about `(1-1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` slots it is roughly `(1-1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
|
||||
|
||||
### Status codes
|
||||
|
||||
|
@ -202,14 +206,15 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
| `EXITED_WITHOUT_PENALTY` | `3` |
|
||||
| `EXITED_WITH_PENALTY` | `4` |
|
||||
|
||||
### Special record types
|
||||
### Max operations per block
|
||||
|
||||
| Name | Value | Maximum count |
|
||||
| - | - | :-: |
|
||||
| `VOLUNTARY_EXIT` | `0` | `16` |
|
||||
| `CASPER_SLASHING` | `1` | `16` |
|
||||
| `PROPOSER_SLASHING` | `2` | `16` |
|
||||
| `DEPOSIT_PROOF` | `3` | `16` |
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `MAX_PROPOSER_SLASHINGS` | `2**4` (= 16) |
|
||||
| `MAX_CASPER_SLASHINGS` | `2**4` (= 16) |
|
||||
| `MAX_ATTESTATIONS` | `2**7` (= 128) |
|
||||
| `MAX_DEPOSITS` | `2**4` (= 16) |
|
||||
| `MAX_EXITS` | `2**4` (= 16) |
|
||||
|
||||
### Validator registry delta flags
|
||||
|
||||
|
@ -229,59 +234,58 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
|
||||
## Data structures
|
||||
|
||||
### Deposits
|
||||
### Beacon chain operations
|
||||
|
||||
#### `DepositParametersRecord`
|
||||
#### Proposer slashings
|
||||
|
||||
##### `ProposerSlashing`
|
||||
|
||||
```python
|
||||
{
|
||||
# BLS pubkey
|
||||
'pubkey': 'uint384',
|
||||
# BLS proof of possession (a BLS signature)
|
||||
'proof_of_possession': ['uint384'],
|
||||
# Withdrawal credentials
|
||||
'withdrawal_credentials': 'hash32',
|
||||
# Initial RANDAO commitment
|
||||
'randao_commitment': 'hash32',
|
||||
# Proposer index
|
||||
'proposer_index': 'uint24',
|
||||
# First proposal data
|
||||
'proposal_data_1': ProposalSignedData,
|
||||
# First proposal signature
|
||||
'proposal_signature_1': '[uint384]',
|
||||
# Second proposal data
|
||||
'proposal_data_2': ProposalSignedData,
|
||||
# Second proposal signature
|
||||
'proposal_signature_2': '[uint384]',
|
||||
}
|
||||
```
|
||||
|
||||
### Beacon chain blocks
|
||||
#### Casper slashings
|
||||
|
||||
#### `BeaconBlockHeader`
|
||||
##### `CasperSlashing`
|
||||
|
||||
```python
|
||||
{
|
||||
'slot': 'uint64',
|
||||
# Skip list of ancestor beacon block hashes
|
||||
# i'th item is the most recent ancestor whose slot is a multiple of 2**i for i = 0, ..., 31
|
||||
'ancestor_hashes': ['hash32'],
|
||||
'state_root': 'hash32',
|
||||
'randao_reveal': 'hash32',
|
||||
'candidate_pow_receipt_root': 'hash32',
|
||||
'signature': ['uint384'],
|
||||
# First batch of votes
|
||||
'votes_1': SlashableVoteData,
|
||||
# Second batch of votes
|
||||
'votes_2': SlashableVoteData,
|
||||
}
|
||||
```
|
||||
|
||||
#### `BeaconBlockBody`
|
||||
##### `SlashableVoteData`
|
||||
|
||||
```python
|
||||
{
|
||||
'attestations': [AttestationRecord],
|
||||
'specials': [SpecialRecord],
|
||||
# Proof-of-custody indices (0 bits)
|
||||
'aggregate_signature_poc_0_indices': '[uint24]',
|
||||
# Proof-of-custody indices (1 bits)
|
||||
'aggregate_signature_poc_1_indices': '[uint24]',
|
||||
# Attestation data
|
||||
'data': AttestationData,
|
||||
# Aggregate signature
|
||||
'aggregate_signature': '[uint384]',
|
||||
}
|
||||
```
|
||||
|
||||
#### `BeaconBlock`
|
||||
#### Attestations
|
||||
|
||||
```python
|
||||
{
|
||||
'header': BeaconBlockHeader,
|
||||
'body': BeaconBlockBody,
|
||||
}
|
||||
```
|
||||
|
||||
#### `AttestationRecord`
|
||||
##### `Attestation`
|
||||
|
||||
```python
|
||||
{
|
||||
|
@ -296,7 +300,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
}
|
||||
```
|
||||
|
||||
#### `AttestationData`
|
||||
##### `AttestationData`
|
||||
|
||||
```python
|
||||
{
|
||||
|
@ -319,6 +323,91 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
}
|
||||
```
|
||||
|
||||
#### Deposits
|
||||
|
||||
##### `Deposit`
|
||||
|
||||
```python
|
||||
{
|
||||
# Receipt Merkle branch
|
||||
'merkle_branch': '[hash32]',
|
||||
# Merkle tree index
|
||||
'merkle_tree_index': 'uint64',
|
||||
# Deposit data
|
||||
'deposit_data': {
|
||||
# Deposit parameters
|
||||
'deposit_parameters': DepositParameters,
|
||||
# Value in Gwei
|
||||
'value': 'uint64',
|
||||
# Timestamp from deposit contract
|
||||
'timestamp': 'uint64',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
##### `DepositParameters`
|
||||
|
||||
```python
|
||||
{
|
||||
# BLS pubkey
|
||||
'pubkey': 'uint384',
|
||||
# BLS proof of possession (a BLS signature)
|
||||
'proof_of_possession': ['uint384'],
|
||||
# Withdrawal credentials
|
||||
'withdrawal_credentials': 'hash32',
|
||||
# Initial RANDAO commitment
|
||||
'randao_commitment': 'hash32',
|
||||
}
|
||||
```
|
||||
|
||||
#### Exits
|
||||
|
||||
##### `Exit`
|
||||
|
||||
```python
|
||||
{
|
||||
# Minimum slot for processing exit
|
||||
'slot': 'unit64',
|
||||
# Index of the exiting validator
|
||||
'validator_index': 'uint64',
|
||||
# Validator signature
|
||||
'signature': '[uint384]',
|
||||
}
|
||||
```
|
||||
|
||||
### Beacon chain blocks
|
||||
|
||||
#### `BeaconBlock`
|
||||
|
||||
```python
|
||||
{
|
||||
## Header ##
|
||||
'slot': 'uint64',
|
||||
# Skip list of ancestor beacon block hashes
|
||||
# i'th item is the most recent ancestor whose slot is a multiple of 2**i for i = 0, ..., 31
|
||||
'ancestor_hashes': ['hash32'],
|
||||
'state_root': 'hash32',
|
||||
'randao_reveal': 'hash32',
|
||||
'candidate_pow_receipt_root': 'hash32',
|
||||
'signature': ['uint384'],
|
||||
|
||||
## Body ##
|
||||
'body': BeaconBlockBody,
|
||||
}
|
||||
```
|
||||
|
||||
#### `BeaconBlockBody`
|
||||
|
||||
```python
|
||||
{
|
||||
'attestations': [Attestation],
|
||||
'proposer_slashings': [ProposerSlashing],
|
||||
'casper_slashings': [CasperSlashing],
|
||||
'deposits': [Deposit],
|
||||
'exits': [Exit],
|
||||
}
|
||||
```
|
||||
|
||||
#### `ProposalSignedData`
|
||||
|
||||
```python
|
||||
|
@ -332,17 +421,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
}
|
||||
```
|
||||
|
||||
#### `SpecialRecord`
|
||||
|
||||
```python
|
||||
{
|
||||
# Kind
|
||||
'kind': 'uint64',
|
||||
# Data
|
||||
'data': 'bytes',
|
||||
}
|
||||
```
|
||||
|
||||
### Beacon chain state
|
||||
|
||||
#### `BeaconState`
|
||||
|
@ -484,93 +562,15 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
|||
}
|
||||
```
|
||||
|
||||
### Specials
|
||||
|
||||
#### `VoluntaryExitSpecial`
|
||||
|
||||
```python
|
||||
{
|
||||
# Minimum slot for processing exit
|
||||
'slot': 'unit64',
|
||||
# Index of the exiting validator
|
||||
'validator_index': 'uint64',
|
||||
# Validator signature
|
||||
'signature': '[uint384]',
|
||||
}
|
||||
```
|
||||
|
||||
#### `CasperSlashingSpecial`
|
||||
|
||||
```python
|
||||
{
|
||||
# First vote
|
||||
vote_1: SpecialAttestationData,
|
||||
# Second vote
|
||||
vote_2: SpecialAttestationData,
|
||||
}
|
||||
```
|
||||
|
||||
#### `SpecialAttestationData`
|
||||
|
||||
```python
|
||||
{
|
||||
# Proof-of-custody indices (0 bits)
|
||||
'aggregate_signature_poc_0_indices': '[uint24]',
|
||||
# Proof-of-custody indices (1 bits)
|
||||
'aggregate_signature_poc_1_indices': '[uint24]',
|
||||
# Attestation data
|
||||
'data': AttestationData,
|
||||
# Aggregate signature
|
||||
'aggregate_signature': '[uint384]',
|
||||
}
|
||||
```
|
||||
|
||||
#### `ProposerSlashingSpecial`
|
||||
|
||||
```python
|
||||
{
|
||||
# Proposer index
|
||||
'proposer_index': 'uint24',
|
||||
# First proposal data
|
||||
'proposal_data_1': ProposalSignedData,
|
||||
# First proposal signature
|
||||
'proposal_signature_1': '[uint384]',
|
||||
# Second proposal data
|
||||
'proposal_data_2': ProposalSignedData,
|
||||
# Second proposal signature
|
||||
'proposal_signature_2': '[uint384]',
|
||||
}
|
||||
```
|
||||
|
||||
#### `DepositProofSpecial`
|
||||
|
||||
```python
|
||||
{
|
||||
# Receipt Merkle branch
|
||||
'merkle_branch': '[hash32]',
|
||||
# Merkle tree index
|
||||
'merkle_tree_index': 'uint64',
|
||||
# Deposit data
|
||||
'deposit_data': {
|
||||
# Deposit parameters
|
||||
'deposit_parameters': DepositParametersRecord,
|
||||
# Value in Gwei
|
||||
'value': 'uint64',
|
||||
# Timestamp from deposit contract
|
||||
'timestamp': 'uint64',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Ethereum 1.0 deposit contract
|
||||
|
||||
The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards when the EVM2.0 is deployed and the shards have state.
|
||||
|
||||
### Deposit arguments
|
||||
|
||||
The deposit contract has a single `deposit` function which takes as argument a SimpleSerialize'd `DepositParametersRecord` object. One of the `DepositParametersRecord` fields is `withdrawal_credentials` which must satisfy:
|
||||
The deposit contract has a single `deposit` function which takes as argument a SimpleSerialize'd `DepositParameters`. One of the `DepositParameters` fields is `withdrawal_credentials` which must satisfy:
|
||||
|
||||
* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_CREDENTIALS`
|
||||
* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE`
|
||||
* `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey
|
||||
|
||||
We recommend the private key corresponding to `withdrawal_pubkey` be stored in cold storage until a withdrawal is required.
|
||||
|
@ -650,10 +650,10 @@ Processing the beacon chain is similar to processing the Ethereum 1.0 chain. Cli
|
|||
|
||||
For a beacon chain block, `block`, to be processed by a node, the following conditions must be met:
|
||||
|
||||
* The parent block with hash `block.header.ancestor_hashes[0]` has been processed and accepted.
|
||||
* The node has processed its `state` up to slot, `block.header.slot - 1`.
|
||||
* The parent block with hash `block.ancestor_hashes[0]` has been processed and accepted.
|
||||
* The node has processed its `state` up to slot, `block.slot - 1`.
|
||||
* The Ethereum 1.0 block pointed to by the `state.processed_pow_receipt_root` has been processed and accepted.
|
||||
* The node's local clock time is greater than or equal to `state.genesis_time + block.header.slot * SLOT_DURATION`.
|
||||
* The node's local clock time is greater than or equal to `state.genesis_time + block.slot * SLOT_DURATION`.
|
||||
|
||||
If these conditions are not met, the client should delay processing the beacon block until the conditions are all satisfied.
|
||||
|
||||
|
@ -666,7 +666,7 @@ The beacon chain fork choice rule is a hybrid that combines justification and fi
|
|||
* Let `store` be the set of attestations and blocks that the [validator](#dfn-validator) `v` has observed and verified (in particular, block ancestors must be recursively verified). Attestations not part of any chain are still included in `store`.
|
||||
* Let `finalized_head` be the finalized block with the highest slot number. (A block `B` is finalized if there is a descendant of `B` in `store` the processing of which sets `B` as finalized.)
|
||||
* Let `justified_head` be the descendant of `finalized_head` with the highest slot number that has been justified for at least `EPOCH_LENGTH` slots. (A block `B` is justified if there is a descendant of `B` in `store` the processing of which sets `B` as justified.) If no such descendant exists set `justified_head` to `finalized_head`.
|
||||
* Let `get_ancestor(store, block, slot)` be the ancestor of `block` with slot number `slot`. The `get_ancestor` function can be defined recursively as `def get_ancestor(store, block, slot): return block if block.header.slot == slot else get_ancestor(store, store.get_parent(block), slot)`.
|
||||
* Let `get_ancestor(store, block, slot)` be the ancestor of `block` with slot number `slot`. The `get_ancestor` function can be defined recursively as `def get_ancestor(store, block, slot): return block if block.slot == slot else get_ancestor(store, store.get_parent(block), slot)`.
|
||||
* Let `get_latest_attestation(store, validator)` be the attestation with the highest slot number in `store` from `validator`. If several such attestations exist, use the one the [validator](#dfn-validator) `v` observed first.
|
||||
* Let `get_latest_attestation_target(store, validator)` be the target block in the attestation `get_latest_attestation(store, validator)`.
|
||||
* The head is `lmd_ghost(store, justified_head)` where the function `lmd_ghost` is defined below. Note that the implementation below is suboptimal; there are implementations that compute the head in time logarithmic in slot count.
|
||||
|
@ -680,7 +680,7 @@ def lmd_ghost(store, start):
|
|||
for validator in active_validators]
|
||||
def get_vote_count(block):
|
||||
return len([target for target in attestation_targets if
|
||||
get_ancestor(store, target, block.header.slot) == block])
|
||||
get_ancestor(store, target, block.slot) == block])
|
||||
|
||||
head = start
|
||||
while 1:
|
||||
|
@ -704,8 +704,7 @@ The per-slot transitions generally focus on verifying aggregate signatures and s
|
|||
Note: The definitions below are for specification purposes and are not necessarily optimal implementations.
|
||||
|
||||
#### `is_active_validator`
|
||||
|
||||
```python
|
||||
```python
|
||||
def is_active_validator(validator: ValidatorRecord) -> bool:
|
||||
"""
|
||||
Checks if ``validator`` is active.
|
||||
|
@ -897,9 +896,9 @@ def get_beacon_proposer_index(state: BeaconState,
|
|||
```python
|
||||
def get_updated_ancestor_hashes(latest_block: BeaconBlock,
|
||||
latest_hash: Hash32) -> List[Hash32]:
|
||||
new_ancestor_hashes = copy.deepcopy(latest_block.header.ancestor_hashes)
|
||||
new_ancestor_hashes = copy.deepcopy(latest_block.ancestor_hashes)
|
||||
for i in range(32):
|
||||
if latest_block.header.slot % 2**i == 0:
|
||||
if latest_block.slot % 2**i == 0:
|
||||
new_ancestor_hashes[i] = latest_hash
|
||||
return new_ancestor_hashes
|
||||
```
|
||||
|
@ -956,7 +955,7 @@ def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_
|
|||
current_validator_registry_delta_chain_tip +
|
||||
bytes1(flag) +
|
||||
bytes3(index) +
|
||||
bytes32(pubkey)
|
||||
bytes48(pubkey)
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -972,6 +971,18 @@ def get_domain(fork_data: ForkData,
|
|||
) * 2**32 + domain_type
|
||||
```
|
||||
|
||||
#### `verify_casper_votes`
|
||||
|
||||
```python
|
||||
def verify_casper_votes(state: BeaconState, votes: SlashableVoteData) -> bool:
|
||||
if len(votes.aggregate_signature_poc_0_indices) + len(votes.aggregate_signature_poc_1_indices) > MAX_CASPER_VOTES:
|
||||
return False
|
||||
|
||||
pubs = [aggregate_pubkey([state.validators[i].pubkey for i in votes.aggregate_signature_poc_0_indices]),
|
||||
aggregate_pubkey([state.validators[i].pubkey for i in votes.aggregate_signature_poc_1_indices])]
|
||||
return BLSMultiVerify(pubkeys=pubs, msgs=[SSZTreeHash(votes)+bytes1(0), SSZTreeHash(votes)+bytes1(1), sig=aggregate_signature)
|
||||
```
|
||||
|
||||
#### `integer_squareroot`
|
||||
|
||||
```python
|
||||
|
@ -993,14 +1004,21 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow
|
|||
|
||||
```python
|
||||
{
|
||||
'slot': INITIAL_SLOT_NUMBER,
|
||||
'randao_reveal': ZERO_HASH,
|
||||
'candidate_pow_receipt_root': ZERO_HASH,
|
||||
'ancestor_hashes': [ZERO_HASH for i in range(32)],
|
||||
'state_root': STARTUP_STATE_ROOT,
|
||||
'attestations': [],
|
||||
'specials': [],
|
||||
'proposer_signature': [0, 0],
|
||||
'header': BeaconBlockHeader(
|
||||
slot=INITIAL_SLOT_NUMBER,
|
||||
ancestor_hashes=[ZERO_HASH for i in range(32)],
|
||||
state_root=STARTUP_STATE_ROOT,
|
||||
randao_reveal=ZERO_HASH,
|
||||
candidate_pow_receipt_root=ZERO_HASH,
|
||||
proposer_signature=[0, 0]
|
||||
),
|
||||
'body': BeaconBlockBody(
|
||||
proposer_slashings=[],
|
||||
casper_slashings=[],
|
||||
attestations=[],
|
||||
deposits=[],
|
||||
exits=[]
|
||||
),
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1025,12 +1043,15 @@ def on_startup(initial_validator_entries: List[Any],
|
|||
proof_of_possession=proof_of_possession,
|
||||
withdrawal_credentials=withdrawal_credentials,
|
||||
randao_commitment=randao_commitment,
|
||||
current_slot=INITIAL_SLOT_NUMBER,
|
||||
status=ACTIVE,
|
||||
current_slot=INITIAL_SLOT_NUMBER,
|
||||
)
|
||||
|
||||
# Setup state
|
||||
initial_shuffling = get_new_shuffling(ZERO_HASH, initial_validator_registry, 0)
|
||||
active_validator_indices = get_active_validator_indices(initial_validator_registry)
|
||||
initial_persistent_committees = split(shuffle(active_validator_indices, ZERO_HASH), SHARD_COUNT)
|
||||
|
||||
state = BeaconState(
|
||||
# Misc
|
||||
slot=INITIAL_SLOT_NUMBER,
|
||||
|
@ -1051,7 +1072,7 @@ def on_startup(initial_validator_entries: List[Any],
|
|||
randao_mix=ZERO_HASH,
|
||||
next_seed=ZERO_HASH,
|
||||
shard_committees_at_slots=initial_shuffling + initial_shuffling,
|
||||
persistent_committees=split(shuffle(initial_validator_registry, ZERO_HASH), SHARD_COUNT),
|
||||
persistent_committees=initial_persistent_committees,
|
||||
persistent_committee_reassignments=[],
|
||||
|
||||
# Finality
|
||||
|
@ -1156,8 +1177,7 @@ def process_deposit(state: BeaconState,
|
|||
proof_of_possession: bytes,
|
||||
withdrawal_credentials: Hash32,
|
||||
randao_commitment: Hash32,
|
||||
status: int,
|
||||
current_slot: int) -> int:
|
||||
status: int) -> int:
|
||||
"""
|
||||
Process a deposit from Ethereum 1.0.
|
||||
Note that this function mutates ``state``.
|
||||
|
@ -1175,7 +1195,7 @@ def process_deposit(state: BeaconState,
|
|||
withdrawal_credentials=withdrawal_credentials,
|
||||
randao_commitment=randao_commitment,
|
||||
status=status,
|
||||
current_slot=current_slot,
|
||||
current_slot=state.slot,
|
||||
)
|
||||
|
||||
return index
|
||||
|
@ -1186,7 +1206,7 @@ def process_deposit(state: BeaconState,
|
|||
```python
|
||||
def exit_validator(index: int,
|
||||
state: BeaconState,
|
||||
new_status: int) -> None:
|
||||
new_status: bool) -> None:
|
||||
"""
|
||||
Exit the validator with the given ``index``.
|
||||
Note that this function mutates ``state``.
|
||||
|
@ -1205,7 +1225,7 @@ def exit_validator(index: int,
|
|||
committee.pop(i)
|
||||
break
|
||||
|
||||
if new_status == EXITED_WITH_PENALTY:
|
||||
if penalize:
|
||||
state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(validator)
|
||||
|
||||
whistleblower = state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
||||
|
@ -1231,23 +1251,71 @@ Below are the processing steps that happen at every slot.
|
|||
* Set `state.latest_block_hashes = state.latest_block_hashes + [latest_hash]`. (The output of `get_block_hash` should not change, except that it will no longer throw for `state.slot - 1`).
|
||||
|
||||
If there is a block from the proposer for `state.slot`, we process that incoming block:
|
||||
|
||||
* Let `block` be that associated incoming block.
|
||||
* Verify that `block.header.slot == state.slot`
|
||||
* Verify that `block.header.ancestor_hashes` equals `get_updated_ancestor_hashes(latest_block, latest_hash)`.
|
||||
* Verify that `block.slot == state.slot`
|
||||
* Verify that `block.ancestor_hashes` equals `get_updated_ancestor_hashes(latest_block, latest_hash)`.
|
||||
|
||||
If there is no block from the proposer at state.slot:
|
||||
|
||||
* Set `state.validator_registry[get_beacon_proposer_index(state, state.slot)].randao_skips += 1`.
|
||||
* Skip all other per-slot processing. Move directly to [per-epoch processing](#per-epoch-processing).
|
||||
|
||||
### Proposer signature
|
||||
|
||||
* Let `block_hash_without_sig` be the hash of `block` where `block.header.signature` is set to `[0, 0]`.
|
||||
* Let `block_hash_without_sig` be the hash of `block` where `block.signature` is set to `[0, 0]`.
|
||||
* Let `proposal_hash = hash(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_hash_without_sig))`.
|
||||
* Verify that `BLSVerify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, data=proposal_hash, sig=block.header.signature, domain=get_domain(state.fork_data, state.slot, DOMAIN_PROPOSAL))`.
|
||||
* Verify that `BLSVerify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, data=proposal_hash, sig=block.signature, domain=get_domain(state.fork_data, state.slot, DOMAIN_PROPOSAL))`.
|
||||
|
||||
### Attestations
|
||||
### RANDAO
|
||||
|
||||
* Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS_PER_BLOCK`.
|
||||
* Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`.
|
||||
* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`.
|
||||
* Verify that `repeat_hash(block.randao_reveal, proposer.randao_skips + 1) == proposer.randao_commitment`.
|
||||
* Set `state.randao_mix = xor(state.randao_mix, block.randao_reveal)`.
|
||||
* Set `proposer.randao_commitment = block.randao_reveal`.
|
||||
* Set `proposer.randao_skips = 0`.
|
||||
|
||||
### PoW receipt root
|
||||
|
||||
* If `block.candidate_pow_receipt_root` is `x.candidate_pow_receipt_root` for some `x` in `state.candidate_pow_receipt_roots`, set `x.votes += 1`.
|
||||
* Otherwise, append to `state.candidate_pow_receipt_roots` a new `CandidatePoWReceiptRootRecord(candidate_pow_receipt_root=block.candidate_pow_receipt_root, votes=1)`.
|
||||
|
||||
### Block operations
|
||||
|
||||
#### Proposer slashings
|
||||
|
||||
Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`.
|
||||
|
||||
For each `proposer_slashing` in `block.body.proposer_slashings`:
|
||||
|
||||
* Let `proposer = state.validator_registry[proposer_slashing.proposer_index]`.
|
||||
* Verify that `BLSVerify(pubkey=proposer.pubkey, msg=hash(proposer_slashing.proposal_data_1), sig=proposer_slashing.proposal_signature_1, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_1.slot, DOMAIN_PROPOSAL))`.
|
||||
* Verify that `BLSVerify(pubkey=proposer.pubkey, msg=hash(proposer_slashing.proposal_data_2), sig=proposer_slashing.proposal_signature_2, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_2.slot, DOMAIN_PROPOSAL))`.
|
||||
* Verify that `proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot`.
|
||||
* Verify that `proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard`.
|
||||
* Verify that `proposer_slashing.proposal_data_1.block_hash != proposer_slashing.proposal_data_2.block_hash`.
|
||||
* Verify that `proposer.status != EXITED_WITH_PENALTY`.
|
||||
* Run `exit_validator(proposer_slashing.proposer_index, state, new_status=EXITED_WITH_PENALTY)`.
|
||||
|
||||
#### Casper slashings
|
||||
|
||||
Verify that `len(block.body.casper_slashings) <= MAX_CASPER_SLASHINGS`.
|
||||
|
||||
For each `casper_slashing` in `block.body.casper_slashings`:
|
||||
|
||||
* Verify that `verify_casper_votes(state, casper_slashing.votes_1)`.
|
||||
* Verify that `verify_casper_votes(state, casper_slashing.votes_2)`.
|
||||
* Verify that `casper_slashing.votes_1.data != casper_slashing.votes_2.data`.
|
||||
* Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`.
|
||||
* Let `intersection = [x for x in indices(casper_slashing.votes_1) if x in indices(casper_slashing.votes_2)]`.
|
||||
* Verify that `len(intersection) >= 1`.
|
||||
* Verify that `casper_slashing.votes_1.data.justified_slot + 1 < casper_slashing.votes_2.data.justified_slot + 1 == casper_slashing.votes_2.data.slot < casper_slashing.votes_1.data.slot` or `casper_slashing.votes_1.data.slot == casper_slashing.votes_2.data.slot`.
|
||||
* For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `exit_validator(i, state, penalize=True, new_status=EXITED_WITH_PENALTY)`
|
||||
|
||||
#### Attestations
|
||||
|
||||
Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`.
|
||||
|
||||
For each `attestation` in `block.body.attestations`:
|
||||
|
||||
|
@ -1263,75 +1331,14 @@ For each `attestation` in `block.body.attestations`:
|
|||
* [TO BE REMOVED IN PHASE 1] Verify that `shard_block_hash == ZERO_HASH`.
|
||||
* Append `PendingAttestationRecord(data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
|
||||
|
||||
### RANDAO
|
||||
#### Deposits
|
||||
|
||||
* Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`.
|
||||
* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`.
|
||||
* Verify that `repeat_hash(block.header.randao_reveal, proposer.randao_skips + 1) == proposer.randao_commitment`.
|
||||
* Set `state.randao_mix = xor(state.randao_mix, block.header.randao_reveal)`.
|
||||
* Set `proposer.randao_commitment = block.header.randao_reveal`.
|
||||
* Set `proposer.randao_skips = 0`.
|
||||
Verify that `len(block.body.deposits) <= MAX_DEPOSITS`.
|
||||
|
||||
### PoW receipt root
|
||||
For each `deposit` in `block.body.deposits`:
|
||||
|
||||
* If `block.header.candidate_pow_receipt_root` is `x.candidate_pow_receipt_root` for some `x` in `state.candidate_pow_receipt_roots`, set `x.votes += 1`.
|
||||
* Otherwise, append to `state.candidate_pow_receipt_roots` a new `CandidatePoWReceiptRootRecord(candidate_pow_receipt_root=block.header.candidate_pow_receipt_root, votes=1)`.
|
||||
|
||||
### Special objects
|
||||
|
||||
* Verify that the quantity of each type of object in `block.body.specials` is less than or equal to its maximum (see table at the top).
|
||||
* Verify that objects are sorted in order of `kind`. That is, `block.body.specials[i+1].kind >= block.body.specials[i].kind` for `0 <= i < len(block.body.specials-1)`.
|
||||
|
||||
For each `special` in `block.body.specials`:
|
||||
|
||||
* Verify that `special.kind` is a valid value.
|
||||
* Verify that `special.data` deserializes according to the format for the given `kind` (see format definitions in "Data structures" above).
|
||||
* Process `special.data` as specified below for each kind.
|
||||
|
||||
#### `VOLUNTARY_EXIT`
|
||||
|
||||
* Let `validator = state.validator_registry[validator_index]`.
|
||||
* Verify that `BLSVerify(pubkey=validator.pubkey, msg=ZERO_HASH, sig=signature, domain=get_domain(state.fork_data, slot, DOMAIN_EXIT))`.
|
||||
* Verify that `validator.status == ACTIVE`.
|
||||
* Verify that `state.slot >= slot`.
|
||||
* Verify that `state.slot >= validator.latest_status_change_slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD`.
|
||||
* Run `exit_validator(validator_index, state, new_status=ACTIVE_PENDING_EXIT)`.
|
||||
|
||||
#### `CASPER_SLASHING`
|
||||
|
||||
Let `verify_special_attestation_data` be the following helper:
|
||||
|
||||
```python
|
||||
def verify_special_attestation_data(state: BeaconState, obj: SpecialAttestationData) -> bool:
|
||||
pubs = [aggregate_pubkey([state.validators[i].pubkey for i in obj.aggregate_signature_poc_0_indices]),
|
||||
aggregate_pubkey([state.validators[i].pubkey for i in obj.aggregate_signature_poc_1_indices])]
|
||||
return BLSMultiVerify(pubkeys=pubs, msgs=[SSZTreeHash(obj)+bytes1(0), SSZTreeHash(obj)+bytes1(1), sig=aggregate_signature)
|
||||
```
|
||||
|
||||
* Verify that `verify_special_attestation_data(vote_1)`.
|
||||
* Verify that `verify_special_attestation_data(vote_2)`.
|
||||
* Verify that `vote_1.data != vote_2.data`.
|
||||
* Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`.
|
||||
* Let `intersection = [x for x in indices(vote_1) if x in indices(vote_2)]`.
|
||||
* Verify that `len(intersection) >= 1`.
|
||||
* Verify that `vote_1.data.justified_slot + 1 < vote_2.data.justified_slot + 1 == vote_2.data.slot < vote_1.data.slot` or `vote_1.data.slot == vote_2.data.slot`.
|
||||
|
||||
For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `exit_validator(i, state, new_status=EXITED_WITH_PENALTY)`
|
||||
|
||||
#### `PROPOSER_SLASHING`
|
||||
|
||||
* Verify that `BLSVerify(pubkey=state.validator_registry[proposer_index].pubkey, msg=hash(proposal_data_1), sig=proposal_signature_1, domain=get_domain(state.fork_data, proposal_data_1.slot, DOMAIN_PROPOSAL))`.
|
||||
* Verify that `BLSVerify(pubkey=state.validator_registry[proposer_index].pubkey, msg=hash(proposal_data_2), sig=proposal_signature_2, domain=get_domain(state.fork_data, proposal_data_2.slot, DOMAIN_PROPOSAL))`.
|
||||
* Verify that `proposal_data_1 != proposal_data_2`.
|
||||
* Verify that `proposal_data_1.slot == proposal_data_2.slot`.
|
||||
* Verify that `state.validator_registry[proposer_index].status != EXITED_WITH_PENALTY`.
|
||||
* Run `exit_validator(proposer_index, state, new_status=EXITED_WITH_PENALTY)`.
|
||||
|
||||
#### `DEPOSIT_PROOF`
|
||||
|
||||
Let `serialized_deposit_data` be the serialized form of `deposit_data. It should be the `DepositParametersRecord` followed by 8 bytes for `deposit_data.value` and 8 bytes for `deposit_data.timestamp`. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-chain-deposit-contract) of which the hash was placed into the Merkle tree.
|
||||
|
||||
Use the following procedure to verify the `merkle_branch`, setting `leaf=serialized_deposit_data`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH` and `root=state.processed_pow_receipt_root`:
|
||||
* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be the `DepositParameters` followed by 8 bytes for `deposit_data.value` and 8 bytes for `deposit_data.timestamp`. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-chain-deposit-contract) of which the hash was placed into the Merkle tree.
|
||||
* Use the following procedure to verify `deposit.merkle_branch`, setting `leaf=serialized_deposit_data`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH` and `root=state.processed_pow_receipt_root`:
|
||||
|
||||
```python
|
||||
def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, root: Hash32) -> bool:
|
||||
|
@ -1344,27 +1351,39 @@ def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int,
|
|||
return value == root
|
||||
```
|
||||
|
||||
* Verify that `state.slot - (deposit_data.timestamp - state.genesis_time) // SLOT_DURATION < ZERO_BALANCE_VALIDATOR_TTL`.
|
||||
* Verify that `state.slot - (deposit.deposit_data.timestamp - state.genesis_time) // SLOT_DURATION < ZERO_BALANCE_VALIDATOR_TTL`.
|
||||
* Run the following:
|
||||
|
||||
```python
|
||||
process_deposit(
|
||||
state=state,
|
||||
pubkey=deposit_data.deposit_parameters.pubkey,
|
||||
deposit=deposit_data.value,
|
||||
proof_of_possession=deposit_data.deposit_parameters.proof_of_possession,
|
||||
withdrawal_credentials=deposit_data.deposit_parameters.withdrawal_credentials,
|
||||
randao_commitment=deposit_data.deposit_parameters.randao_commitment,
|
||||
status=PENDING_ACTIVATION,
|
||||
current_slot=state.slot
|
||||
pubkey=deposit.deposit_data.deposit_parameters.pubkey,
|
||||
deposit=deposit.deposit_data.value,
|
||||
proof_of_possession=deposit.deposit_data.deposit_parameters.proof_of_possession,
|
||||
withdrawal_credentials=deposit.deposit_data.deposit_parameters.withdrawal_credentials,
|
||||
randao_commitment=deposit.deposit_data.deposit_parameters.randao_commitment,
|
||||
status=PENDING_ACTIVATION
|
||||
)
|
||||
```
|
||||
|
||||
#### Exits
|
||||
|
||||
Verify that `len(block.body.exits) <= MAX_EXITS`.
|
||||
|
||||
For each `exit` in `block.body.exits`:
|
||||
|
||||
* Let `validator = state.validator_registry[exit.validator_index]`.
|
||||
* Verify that `BLSVerify(pubkey=validator.pubkey, msg=ZERO_HASH, sig=exit.signature, domain=get_domain(state.fork_data, exit.slot, DOMAIN_EXIT))`.
|
||||
* Verify that `validator.status == ACTIVE`.
|
||||
* Verify that `state.slot >= exit.slot`.
|
||||
* Verify that `state.slot >= validator.latest_status_change_slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD`.
|
||||
* Run `exit_validator(validator_index, state, new_status=ACTIVE_PENDING_EXIT)`.
|
||||
|
||||
### Ejections
|
||||
|
||||
* Run `process_ejections(state)`.
|
||||
|
||||
```python
|
||||
```python
|
||||
def process_ejections(state: BeaconState) -> None:
|
||||
"""
|
||||
Iterate through the validator registry
|
||||
|
@ -1392,14 +1411,16 @@ All [validators](#dfn-validator):
|
|||
|
||||
* Let `this_epoch_attestations = [a for a in state.latest_attestations if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]`. (Note: this is the set of attestations of slots in the epoch `state.slot-EPOCH_LENGTH...state.slot-1`, _not_ attestations that got included in the chain during the epoch `state.slot-EPOCH_LENGTH...state.slot-1`.)
|
||||
* Let `this_epoch_boundary_attestations = [a for a in this_epoch_attestations if a.data.epoch_boundary_hash == get_block_hash(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`.
|
||||
* Let `this_epoch_boundary_attesters` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`.
|
||||
* Let `this_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`.
|
||||
* Let `this_epoch_boundary_attesters = [state.validator_registry[i] for indices in this_epoch_boundary_attester_indices for i in indices]`.
|
||||
* Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in this_epoch_boundary_attesters])`.
|
||||
|
||||
[Validators](#dfn-Validator) justifying the epoch boundary block at the start of the previous epoch:
|
||||
|
||||
* Let `previous_epoch_attestations = [a for a in state.latest_attestations if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]`.
|
||||
* Let `previous_epoch_boundary_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.epoch_boundary_hash == get_block_hash(state, state.slot - 2 * EPOCH_LENGTH) and a.justified_slot == state.previous_justified_slot]`.
|
||||
* Let `previous_epoch_boundary_attesters` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`.
|
||||
* Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`.
|
||||
* Let `previous_epoch_boundary_attesters = [state.validator_registry[i] for indices in previous_epoch_boundary_attester_indices for i in indices]`.
|
||||
* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`.
|
||||
|
||||
For every `shard_committee` in `state.shard_committees_at_slots`:
|
||||
|
@ -1439,6 +1460,7 @@ If `state.slot % POW_RECEIPT_ROOT_VOTING_PERIOD == 0`:
|
|||
### Finalization
|
||||
|
||||
Set `state.finalized_slot = state.previous_justified_slot` if any of the following are true:
|
||||
|
||||
* `state.previous_justified_slot == state.slot - 2 * EPOCH_LENGTH and state.justification_bitfield % 4 == 3`
|
||||
* `state.previous_justified_slot == state.slot - 3 * EPOCH_LENGTH and state.justification_bitfield % 8 == 7`
|
||||
* `state.previous_justified_slot == state.slot - 4 * EPOCH_LENGTH and state.justification_bitfield % 16 in (15, 14)`
|
||||
|
@ -1626,7 +1648,7 @@ while len(state.persistent_committee_reassignments) > 0 and state.persistent_com
|
|||
|
||||
## State root processing
|
||||
|
||||
Verify `block.header.state_root == hash(state)` if there exists a `block` for the slot being processed.
|
||||
Verify `block.state_root == hash(state)` if there exists a `block` for the slot being processed.
|
||||
|
||||
# Appendix
|
||||
## Appendix A - Hash function
|
||||
|
|
|
@ -56,7 +56,7 @@ overhead.
|
|||
| Constant | Value | Definition |
|
||||
|:------------------|:-----:|:--------------------------------------------------------------------------------------|
|
||||
| `LENGTH_BYTES` | 4 | Number of bytes used for the length added before a variable-length serialized object. |
|
||||
| `SSZ_CHUNK_SIZE` | 128 | Number of bytes for the chuck size of the Merkle tree leaf. |
|
||||
| `SSZ_CHUNK_SIZE` | 128 | Number of bytes for the chunk size of the Merkle tree leaf. |
|
||||
|
||||
|
||||
## Overview
|
||||
|
@ -394,11 +394,11 @@ The below `SSZTreeHash` algorithm is defined recursively in the case of lists an
|
|||
|
||||
We define `hash(x)` as `BLAKE2b-512(x)[0:32]`.
|
||||
|
||||
#### `uintN`, `bool`, `address`, `hash32`
|
||||
#### `uint8`..`uint256`, `bool`, `address`, `hash1`..`hash32`
|
||||
|
||||
Return the serialization of the value.
|
||||
|
||||
#### `bytes`, `hashN`
|
||||
#### `uint264`..`uintN`, `bytes`, `hash33`..`hashN`
|
||||
|
||||
Return the hash of the serialization of the value.
|
||||
|
||||
|
|
Loading…
Reference in New Issue