Merge branch 'master' into bytes32
This commit is contained in:
commit
df83dc7bf5
|
@ -45,12 +45,13 @@
|
||||||
- [`ProposalSignedData`](#proposalsigneddata)
|
- [`ProposalSignedData`](#proposalsigneddata)
|
||||||
- [Beacon chain state](#beacon-chain-state)
|
- [Beacon chain state](#beacon-chain-state)
|
||||||
- [`BeaconState`](#beaconstate)
|
- [`BeaconState`](#beaconstate)
|
||||||
- [`ValidatorRecord`](#validatorrecord)
|
- [`Validator`](#validator)
|
||||||
- [`CrosslinkRecord`](#crosslinkrecord)
|
- [`Crosslink`](#crosslink)
|
||||||
- [`DepositRootVote`](#depositrootvote)
|
- [`PendingAttestation`](#pendingattestation)
|
||||||
- [`PendingAttestationRecord`](#pendingattestationrecord)
|
- [`Fork`](#fork)
|
||||||
- [`ForkData`](#forkdata)
|
|
||||||
- [`ValidatorRegistryDeltaBlock`](#validatorregistrydeltablock)
|
- [`ValidatorRegistryDeltaBlock`](#validatorregistrydeltablock)
|
||||||
|
- [`Eth1Data`](#eth1data)
|
||||||
|
- [`Eth1DataVote`](#eth1datavote)
|
||||||
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
|
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
|
||||||
- [Deposit arguments](#deposit-arguments)
|
- [Deposit arguments](#deposit-arguments)
|
||||||
- [Withdrawal credentials](#withdrawal-credentials)
|
- [Withdrawal credentials](#withdrawal-credentials)
|
||||||
|
@ -99,7 +100,7 @@
|
||||||
- [Slot](#slot)
|
- [Slot](#slot)
|
||||||
- [Proposer signature](#proposer-signature)
|
- [Proposer signature](#proposer-signature)
|
||||||
- [RANDAO](#randao)
|
- [RANDAO](#randao)
|
||||||
- [Deposit root](#deposit-root)
|
- [Eth1 data](#eth1-data)
|
||||||
- [Operations](#operations)
|
- [Operations](#operations)
|
||||||
- [Proposer slashings](#proposer-slashings-1)
|
- [Proposer slashings](#proposer-slashings-1)
|
||||||
- [Casper slashings](#casper-slashings-1)
|
- [Casper slashings](#casper-slashings-1)
|
||||||
|
@ -109,7 +110,7 @@
|
||||||
- [Custody](#custody)
|
- [Custody](#custody)
|
||||||
- [Per-epoch processing](#per-epoch-processing)
|
- [Per-epoch processing](#per-epoch-processing)
|
||||||
- [Helpers](#helpers)
|
- [Helpers](#helpers)
|
||||||
- [Deposit roots](#deposit-roots)
|
- [Eth1 data](#eth1-data-1)
|
||||||
- [Justification](#justification)
|
- [Justification](#justification)
|
||||||
- [Crosslinks](#crosslinks)
|
- [Crosslinks](#crosslinks)
|
||||||
- [Rewards and penalties](#rewards-and-penalties)
|
- [Rewards and penalties](#rewards-and-penalties)
|
||||||
|
@ -164,9 +165,8 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
| - | - | :-: |
|
| - | - | :-: |
|
||||||
| `SHARD_COUNT` | `2**10` (= 1,024) | shards |
|
| `SHARD_COUNT` | `2**10` (= 1,024) | shards |
|
||||||
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | [validators](#dfn-validator) |
|
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | [validators](#dfn-validator) |
|
||||||
| `EJECTION_BALANCE` | `2**4` (= 16) | ETH |
|
| `EJECTION_BALANCE` | `2**4 * 1e9` (= 16,000,000,000) | Gwei |
|
||||||
| `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | - |
|
| `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | - |
|
||||||
| `GWEI_PER_ETH` | `10**9` | Gwei/ETH |
|
|
||||||
| `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - |
|
| `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - |
|
||||||
| `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes |
|
| `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes |
|
||||||
| `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots |
|
| `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots |
|
||||||
|
@ -182,8 +182,8 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
| - | - | :-: |
|
| - | - | :-: |
|
||||||
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** |
|
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** |
|
||||||
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | - |
|
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | - |
|
||||||
| `MIN_DEPOSIT` | `2**0` (= 1) | ETH |
|
| `MIN_DEPOSIT_AMOUNT` | `2**0 * 1e9` (= 1,000,000,000) | Gwei |
|
||||||
| `MAX_DEPOSIT` | `2**5` (= 32) | ETH |
|
| `MAX_DEPOSIT_AMOUNT` | `2**5 * 1e9` (= 32,000,000,000) | Gwei |
|
||||||
|
|
||||||
### Initial values
|
### Initial values
|
||||||
|
|
||||||
|
@ -206,14 +206,14 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
| `EPOCH_LENGTH` | `2**6` (= 64) | slots | 6.4 minutes |
|
| `EPOCH_LENGTH` | `2**6` (= 64) | slots | 6.4 minutes |
|
||||||
| `SEED_LOOKAHEAD` | `2**6` (= 64) | slots | 6.4 minutes |
|
| `SEED_LOOKAHEAD` | `2**6` (= 64) | slots | 6.4 minutes |
|
||||||
| `ENTRY_EXIT_DELAY` | `2**8` (= 256) | slots | 25.6 minutes |
|
| `ENTRY_EXIT_DELAY` | `2**8` (= 256) | slots | 25.6 minutes |
|
||||||
| `DEPOSIT_ROOT_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
|
| `ETH1_DATA_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
|
||||||
| `MIN_VALIDATOR_WITHDRAWAL_TIME` | `2**14` (= 16,384) | slots | ~27 hours |
|
| `MIN_VALIDATOR_WITHDRAWAL_TIME` | `2**14` (= 16,384) | slots | ~27 hours |
|
||||||
|
|
||||||
### Reward and penalty quotients
|
### Reward and penalty quotients
|
||||||
|
|
||||||
| Name | Value |
|
| Name | Value |
|
||||||
| - | - |
|
| - | - |
|
||||||
| `BASE_REWARD_QUOTIENT` | `2**10` (= 1,024) |
|
| `BASE_REWARD_QUOTIENT` | `2**5` (= 32) |
|
||||||
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `2**9` (= 512) |
|
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `2**9` (= 512) |
|
||||||
| `INCLUDER_REWARD_QUOTIENT` | `2**3` (= 8) |
|
| `INCLUDER_REWARD_QUOTIENT` | `2**3` (= 8) |
|
||||||
| `INACTIVITY_PENALTY_QUOTIENT` | `2**24` (= 16,777,216) |
|
| `INACTIVITY_PENALTY_QUOTIENT` | `2**24` (= 16,777,216) |
|
||||||
|
@ -324,8 +324,8 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
{
|
{
|
||||||
# Attestation data
|
# Attestation data
|
||||||
'data': AttestationData,
|
'data': AttestationData,
|
||||||
# Attester participation bitfield
|
# Attester aggregation bitfield
|
||||||
'participation_bitfield': 'bytes',
|
'aggregation_bitfield': 'bytes',
|
||||||
# Custody bitfield
|
# Custody bitfield
|
||||||
'custody_bitfield': 'bytes',
|
'custody_bitfield': 'bytes',
|
||||||
# BLS aggregate signature
|
# BLS aggregate signature
|
||||||
|
@ -438,7 +438,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
'parent_root': 'bytes32',
|
'parent_root': 'bytes32',
|
||||||
'state_root': 'bytes32',
|
'state_root': 'bytes32',
|
||||||
'randao_reveal': 'bytes32',
|
'randao_reveal': 'bytes32',
|
||||||
'deposit_root': 'bytes32',
|
'eth1_data': Eth1Data,
|
||||||
'signature': Signature,
|
'signature': Signature,
|
||||||
|
|
||||||
## Body ##
|
## Body ##
|
||||||
|
@ -485,12 +485,12 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
# Misc
|
# Misc
|
||||||
'slot': 'uint64',
|
'slot': 'uint64',
|
||||||
'genesis_time': 'uint64',
|
'genesis_time': 'uint64',
|
||||||
'fork_data': ForkData, # For versioning hard forks
|
'fork': Fork, # For versioning hard forks
|
||||||
|
|
||||||
# Validator registry
|
# Validator registry
|
||||||
'validator_registry': [ValidatorRecord],
|
'validator_registry': [Validator],
|
||||||
'validator_balances': ['uint64'],
|
'validator_balances': ['uint64'],
|
||||||
'validator_registry_latest_change_slot': 'uint64',
|
'validator_registry_update_slot': 'uint64',
|
||||||
'validator_registry_exit_count': 'uint64',
|
'validator_registry_exit_count': 'uint64',
|
||||||
'validator_registry_delta_chain_tip': 'bytes32', # For light clients to track deltas
|
'validator_registry_delta_chain_tip': 'bytes32', # For light clients to track deltas
|
||||||
|
|
||||||
|
@ -514,19 +514,19 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
'finalized_slot': 'uint64',
|
'finalized_slot': 'uint64',
|
||||||
|
|
||||||
# Recent state
|
# Recent state
|
||||||
'latest_crosslinks': [CrosslinkRecord],
|
'latest_crosslinks': [Crosslink],
|
||||||
'latest_block_roots': ['bytes32'], # Needed to process attestations, older to newer
|
'latest_block_roots': ['bytes32'], # Needed to process attestations, older to newer
|
||||||
'latest_penalized_exit_balances': ['uint64'], # Balances penalized at every withdrawal period
|
'latest_penalized_balances': ['uint64'], # Balances penalized at every withdrawal period
|
||||||
'latest_attestations': [PendingAttestationRecord],
|
'latest_attestations': [PendingAttestation],
|
||||||
'batched_block_roots': ['bytes32'],
|
'batched_block_roots': ['bytes32'],
|
||||||
|
|
||||||
# Ethereum 1.0 deposit root
|
# Ethereum 1.0 chain data
|
||||||
'latest_deposit_root': 'bytes32',
|
'latest_eth1_data': Eth1Data,
|
||||||
'deposit_root_votes': [DepositRootVote],
|
'eth1_data_votes': [Eth1DataVote],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `ValidatorRecord`
|
#### `Validator`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
|
@ -559,7 +559,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `CrosslinkRecord`
|
#### `Crosslink`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
|
@ -570,25 +570,14 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `DepositRootVote`
|
#### `PendingAttestation`
|
||||||
|
|
||||||
```python
|
|
||||||
{
|
|
||||||
# Deposit root
|
|
||||||
'deposit_root': 'bytes32',
|
|
||||||
# Vote count
|
|
||||||
'vote_count': 'uint64',
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `PendingAttestationRecord`
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
# Signed data
|
# Signed data
|
||||||
'data': AttestationData,
|
'data': AttestationData,
|
||||||
# Attester participation bitfield
|
# Attester aggregation bitfield
|
||||||
'participation_bitfield': 'bytes',
|
'aggregation_bitfield': 'bytes',
|
||||||
# Custody bitfield
|
# Custody bitfield
|
||||||
'custody_bitfield': 'bytes',
|
'custody_bitfield': 'bytes',
|
||||||
# Slot the attestation was included
|
# Slot the attestation was included
|
||||||
|
@ -596,16 +585,16 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `ForkData`
|
#### `Fork`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
# Previous fork version
|
# Previous fork version
|
||||||
'pre_fork_version': 'uint64',
|
'previous_version': 'uint64',
|
||||||
# Post fork version
|
# Current fork version
|
||||||
'post_fork_version': 'uint64',
|
'current_version': 'uint64',
|
||||||
# Fork slot number
|
# Fork slot number
|
||||||
'fork_slot': 'uint64',
|
'slot': 'uint64',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -613,11 +602,33 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
latest_registry_delta_root: 'bytes32',
|
'latest_registry_delta_root': 'bytes32',
|
||||||
validator_index: 'uint24',
|
'validator_index': 'uint24',
|
||||||
pubkey: 'bytes48',
|
'pubkey': 'bytes48',
|
||||||
slot: 'uint64',
|
'slot': 'uint64',
|
||||||
flag: 'uint64',
|
'flag': 'uint64',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `Eth1Data`
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
# Root of the deposit tree
|
||||||
|
'deposit_root': 'hash32',
|
||||||
|
# Block hash
|
||||||
|
'block_hash': 'hash32',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `Eth1DataVote`
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
# Data being voted for
|
||||||
|
'eth1_data': Eth1Data,
|
||||||
|
# Vote count
|
||||||
|
'vote_count': 'uint64',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -640,14 +651,14 @@ The private key corresponding to `withdrawal_pubkey` will be required to initiat
|
||||||
|
|
||||||
### `Deposit` logs
|
### `Deposit` logs
|
||||||
|
|
||||||
Every Ethereum 1.0 deposit, of size between `MIN_DEPOSIT` and `MAX_DEPOSIT`, emits a `Deposit` 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 BLS signature) is not verified by the deposit contract.
|
Every Ethereum 1.0 deposit, of size between `MIN_DEPOSIT_AMOUNT` and `MAX_DEPOSIT_AMOUNT`, emits a `Deposit` 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 signature) is not verified by the deposit contract.
|
||||||
|
|
||||||
### `ChainStart` log
|
### `ChainStart` log
|
||||||
|
|
||||||
When sufficiently many full deposits have been made the deposit contract emits the `ChainStart` log. The beacon chain state may then be initialized by calling the `get_initial_beacon_state` function (defined below) where:
|
When sufficiently many full deposits have been made the deposit contract emits the `ChainStart` log. The beacon chain state may then be initialized by calling the `get_initial_beacon_state` function (defined below) where:
|
||||||
|
|
||||||
* `genesis_time` equals `time` in the `ChainStart` log
|
* `genesis_time` equals `time` in the `ChainStart` log
|
||||||
* `latest_deposit_root` equals `deposit_root` in the `ChainStart` log
|
* `latest_eth1_data.deposit_root` equals `deposit_root` in the `ChainStart` log, and `latest_eth1_data.block_hash` equals the hash of the block that included the log
|
||||||
* `initial_validator_deposits` is a list of `Deposit` objects built according to the `Deposit` logs up to the deposit that triggered the `ChainStart` log, processed in the order in which they were emitted (oldest to newest)
|
* `initial_validator_deposits` is a list of `Deposit` objects built according to the `Deposit` logs up to the deposit that triggered the `ChainStart` log, processed in the order in which they were emitted (oldest to newest)
|
||||||
|
|
||||||
### Vyper code
|
### Vyper code
|
||||||
|
@ -655,8 +666,8 @@ When sufficiently many full deposits have been made the deposit contract emits t
|
||||||
```python
|
```python
|
||||||
## compiled with v0.1.0-beta.6 ##
|
## compiled with v0.1.0-beta.6 ##
|
||||||
|
|
||||||
MIN_DEPOSIT: constant(uint256) = 1 # ETH
|
MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei
|
||||||
MAX_DEPOSIT: constant(uint256) = 32 # ETH
|
MAX_DEPOSIT_AMOUNT: constant(uint256) = 32000000000 # Gwei
|
||||||
GWEI_PER_ETH: constant(uint256) = 1000000000 # 10**9
|
GWEI_PER_ETH: constant(uint256) = 1000000000 # 10**9
|
||||||
CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = 16384 # 2**14
|
CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = 16384 # 2**14
|
||||||
DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
|
DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
|
||||||
|
@ -673,13 +684,13 @@ full_deposit_count: uint256
|
||||||
@payable
|
@payable
|
||||||
@public
|
@public
|
||||||
def deposit(deposit_input: bytes[2048]):
|
def deposit(deposit_input: bytes[2048]):
|
||||||
assert msg.value >= as_wei_value(MIN_DEPOSIT, "ether")
|
assert msg.value >= as_wei_value(MIN_DEPOSIT_AMOUNT, "gwei")
|
||||||
assert msg.value <= as_wei_value(MAX_DEPOSIT, "ether")
|
assert msg.value <= as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei")
|
||||||
|
|
||||||
index: uint256 = self.deposit_count + TWO_TO_POWER_OF_TREE_DEPTH
|
index: uint256 = self.deposit_count + TWO_TO_POWER_OF_TREE_DEPTH
|
||||||
msg_gwei_bytes8: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8)
|
deposit_amount: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8)
|
||||||
timestamp_bytes8: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8)
|
deposit_timestamp: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8)
|
||||||
deposit_data: bytes[2064] = concat(msg_gwei_bytes8, timestamp_bytes8, deposit_input)
|
deposit_data: bytes[2064] = concat(deposit_amount, deposit_timestamp, deposit_input)
|
||||||
merkle_tree_index: bytes[8] = slice(concat("", convert(index, bytes32)), start=24, len=8)
|
merkle_tree_index: bytes[8] = slice(concat("", convert(index, bytes32)), start=24, len=8)
|
||||||
|
|
||||||
log.Deposit(self.deposit_tree[1], deposit_data, merkle_tree_index)
|
log.Deposit(self.deposit_tree[1], deposit_data, merkle_tree_index)
|
||||||
|
@ -691,12 +702,12 @@ def deposit(deposit_input: bytes[2048]):
|
||||||
self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1]))
|
self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1]))
|
||||||
|
|
||||||
self.deposit_count += 1
|
self.deposit_count += 1
|
||||||
if msg.value == as_wei_value(MAX_DEPOSIT, "ether"):
|
if msg.value == as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei"):
|
||||||
self.full_deposit_count += 1
|
self.full_deposit_count += 1
|
||||||
if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD:
|
if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD:
|
||||||
timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY
|
timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY
|
||||||
timestamp_day_boundary_bytes8: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8)
|
chainstart_time: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8)
|
||||||
log.ChainStart(self.deposit_tree[1], timestamp_day_boundary_bytes8)
|
log.ChainStart(self.deposit_tree[1], chainstart_time)
|
||||||
|
|
||||||
@public
|
@public
|
||||||
@constant
|
@constant
|
||||||
|
@ -728,7 +739,7 @@ For a beacon chain block, `block`, to be processed by a node, the following cond
|
||||||
|
|
||||||
* The parent block with root `block.parent_root` has been processed and accepted.
|
* The parent block with root `block.parent_root` has been processed and accepted.
|
||||||
* The node has processed its `state` up to slot, `block.slot - 1`.
|
* The node has processed its `state` up to slot, `block.slot - 1`.
|
||||||
* An Ethereum 1.0 block pointed to by the `state.latest_deposit_root` has been processed and accepted.
|
* An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted.
|
||||||
* The node's local clock time is greater than or equal to `state.genesis_time + block.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.
|
If these conditions are not met, the client should delay processing the beacon block until the conditions are all satisfied.
|
||||||
|
@ -791,7 +802,7 @@ Note: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethere
|
||||||
|
|
||||||
#### `is_active_validator`
|
#### `is_active_validator`
|
||||||
```python
|
```python
|
||||||
def is_active_validator(validator: ValidatorRecord, slot: int) -> bool:
|
def is_active_validator(validator: Validator, slot: int) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks if ``validator`` is active.
|
Checks if ``validator`` is active.
|
||||||
"""
|
"""
|
||||||
|
@ -801,7 +812,7 @@ def is_active_validator(validator: ValidatorRecord, slot: int) -> bool:
|
||||||
#### `get_active_validator_indices`
|
#### `get_active_validator_indices`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_active_validator_indices(validators: [ValidatorRecord], slot: int) -> List[int]:
|
def get_active_validator_indices(validators: [Validator], slot: int) -> List[int]:
|
||||||
"""
|
"""
|
||||||
Gets indices of active validators from ``validators``.
|
Gets indices of active validators from ``validators``.
|
||||||
"""
|
"""
|
||||||
|
@ -892,7 +903,7 @@ def get_committee_count_per_slot(active_validator_count: int) -> int:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_shuffling(seed: Bytes32,
|
def get_shuffling(seed: Bytes32,
|
||||||
validators: List[ValidatorRecord],
|
validators: List[Validator],
|
||||||
slot: int) -> List[List[int]]
|
slot: int) -> List[List[int]]
|
||||||
"""
|
"""
|
||||||
Shuffles ``validators`` into crosslink committees seeded by ``seed`` and ``slot``.
|
Shuffles ``validators`` into crosslink committees seeded by ``seed`` and ``slot``.
|
||||||
|
@ -1039,9 +1050,9 @@ def merkle_root(values: List[Bytes32]) -> Bytes32:
|
||||||
```python
|
```python
|
||||||
def get_attestation_participants(state: BeaconState,
|
def get_attestation_participants(state: BeaconState,
|
||||||
attestation_data: AttestationData,
|
attestation_data: AttestationData,
|
||||||
participation_bitfield: bytes) -> List[int]:
|
aggregation_bitfield: bytes) -> List[int]:
|
||||||
"""
|
"""
|
||||||
Returns the participant indices at for the ``attestation_data`` and ``participation_bitfield``.
|
Returns the participant indices at for the ``attestation_data`` and ``aggregation_bitfield``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Find the committee in the list with the desired shard
|
# Find the committee in the list with the desired shard
|
||||||
|
@ -1049,13 +1060,13 @@ def get_attestation_participants(state: BeaconState,
|
||||||
|
|
||||||
assert attestation_data.shard in [shard for _, shard in crosslink_committees]
|
assert attestation_data.shard in [shard for _, shard in crosslink_committees]
|
||||||
crosslink_committee = [committee for committee, shard in crosslink_committees if shard == attestation_data.shard][0]
|
crosslink_committee = [committee for committee, shard in crosslink_committees if shard == attestation_data.shard][0]
|
||||||
assert len(participation_bitfield) == (len(committee) + 7) // 8
|
assert len(aggregation_bitfield) == (len(committee) + 7) // 8
|
||||||
|
|
||||||
# Find the participating attesters in the committee
|
# Find the participating attesters in the committee
|
||||||
participants = []
|
participants = []
|
||||||
for i, validator_index in enumerate(crosslink_committee):
|
for i, validator_index in enumerate(crosslink_committee):
|
||||||
participation_bit = (participation_bitfield[i//8] >> (7 - (i % 8))) % 2
|
aggregation_bit = (aggregation_bitfield[i // 8] >> (7 - (i % 8))) % 2
|
||||||
if participation_bit == 1:
|
if aggregation_bit == 1:
|
||||||
participants.append(validator_index)
|
participants.append(validator_index)
|
||||||
return participants
|
return participants
|
||||||
```
|
```
|
||||||
|
@ -1071,28 +1082,28 @@ def get_effective_balance(state: State, index: int) -> int:
|
||||||
"""
|
"""
|
||||||
Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``index``.
|
Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``index``.
|
||||||
"""
|
"""
|
||||||
return min(state.validator_balances[index], MAX_DEPOSIT * GWEI_PER_ETH)
|
return min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_fork_version`
|
#### `get_fork_version`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_fork_version(fork_data: ForkData,
|
def get_fork_version(fork: Fork,
|
||||||
slot: int) -> int:
|
slot: int) -> int:
|
||||||
if slot < fork_data.fork_slot:
|
if slot < fork.slot:
|
||||||
return fork_data.pre_fork_version
|
return fork.previous_version
|
||||||
else:
|
else:
|
||||||
return fork_data.post_fork_version
|
return fork.current_version
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_domain`
|
#### `get_domain`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_domain(fork_data: ForkData,
|
def get_domain(fork: Fork,
|
||||||
slot: int,
|
slot: int,
|
||||||
domain_type: int) -> int:
|
domain_type: int) -> int:
|
||||||
return get_fork_version(
|
return get_fork_version(
|
||||||
fork_data,
|
fork,
|
||||||
slot
|
slot
|
||||||
) * 2**32 + domain_type
|
) * 2**32 + domain_type
|
||||||
```
|
```
|
||||||
|
@ -1115,7 +1126,7 @@ def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData)
|
||||||
],
|
],
|
||||||
signature=signature_to_tuple(vote_data.aggregate_signature),
|
signature=signature_to_tuple(vote_data.aggregate_signature),
|
||||||
domain=get_domain(
|
domain=get_domain(
|
||||||
state.fork_data,
|
state.fork,
|
||||||
state.slot,
|
state.slot,
|
||||||
DOMAIN_ATTESTATION,
|
DOMAIN_ATTESTATION,
|
||||||
),
|
),
|
||||||
|
@ -1208,7 +1219,10 @@ A valid block with slot `GENESIS_SLOT` (a "genesis block") has the following val
|
||||||
parent_root=ZERO_HASH,
|
parent_root=ZERO_HASH,
|
||||||
state_root=STARTUP_STATE_ROOT,
|
state_root=STARTUP_STATE_ROOT,
|
||||||
randao_reveal=ZERO_HASH,
|
randao_reveal=ZERO_HASH,
|
||||||
deposit_root=ZERO_HASH,
|
eth1_data=Eth1Data(
|
||||||
|
deposit_root=ZERO_HASH,
|
||||||
|
block_hash=ZERO_HASH
|
||||||
|
),
|
||||||
signature=EMPTY_SIGNATURE,
|
signature=EMPTY_SIGNATURE,
|
||||||
body=BeaconBlockBody(
|
body=BeaconBlockBody(
|
||||||
proposer_slashings=[],
|
proposer_slashings=[],
|
||||||
|
@ -1228,21 +1242,21 @@ A valid block with slot `GENESIS_SLOT` (a "genesis block") has the following val
|
||||||
```python
|
```python
|
||||||
def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
genesis_time: int,
|
genesis_time: int,
|
||||||
latest_deposit_root: Bytes32) -> BeaconState:
|
latest_eth1_data: Eth1Data) -> BeaconState:
|
||||||
state = BeaconState(
|
state = BeaconState(
|
||||||
# Misc
|
# Misc
|
||||||
slot=GENESIS_SLOT,
|
slot=GENESIS_SLOT,
|
||||||
genesis_time=genesis_time,
|
genesis_time=genesis_time,
|
||||||
fork_data=ForkData(
|
fork=Fork(
|
||||||
pre_fork_version=GENESIS_FORK_VERSION,
|
previous_version=GENESIS_FORK_VERSION,
|
||||||
post_fork_version=GENESIS_FORK_VERSION,
|
current_version=GENESIS_FORK_VERSION,
|
||||||
fork_slot=GENESIS_SLOT,
|
slot=GENESIS_SLOT,
|
||||||
),
|
),
|
||||||
|
|
||||||
# Validator registry
|
# Validator registry
|
||||||
validator_registry=[],
|
validator_registry=[],
|
||||||
validator_balances=[],
|
validator_balances=[],
|
||||||
validator_registry_latest_change_slot=GENESIS_SLOT,
|
validator_registry_update_slot=GENESIS_SLOT,
|
||||||
validator_registry_exit_count=0,
|
validator_registry_exit_count=0,
|
||||||
validator_registry_delta_chain_tip=ZERO_HASH,
|
validator_registry_delta_chain_tip=ZERO_HASH,
|
||||||
|
|
||||||
|
@ -1266,15 +1280,15 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
finalized_slot=GENESIS_SLOT,
|
finalized_slot=GENESIS_SLOT,
|
||||||
|
|
||||||
# Recent state
|
# Recent state
|
||||||
latest_crosslinks=[CrosslinkRecord(slot=GENESIS_SLOT, shard_block_root=ZERO_HASH) for _ in range(SHARD_COUNT)],
|
latest_crosslinks=[Crosslink(slot=GENESIS_SLOT, shard_block_root=ZERO_HASH) for _ in range(SHARD_COUNT)],
|
||||||
latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)],
|
latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)],
|
||||||
latest_penalized_exit_balances=[0 for _ in range(LATEST_PENALIZED_EXIT_LENGTH)],
|
latest_penalized_balances=[0 for _ in range(LATEST_PENALIZED_EXIT_LENGTH)],
|
||||||
latest_attestations=[],
|
latest_attestations=[],
|
||||||
batched_block_roots=[],
|
batched_block_roots=[],
|
||||||
|
|
||||||
# Deposit root
|
# Ethereum 1.0 chain data
|
||||||
latest_deposit_root=latest_deposit_root,
|
latest_eth1_data=latest_eth1_data,
|
||||||
deposit_root_votes=[],
|
eth1_data_votes=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Process initial deposits
|
# Process initial deposits
|
||||||
|
@ -1291,7 +1305,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
|
|
||||||
# Process initial activations
|
# Process initial activations
|
||||||
for validator_index, _ in enumerate(state.validator_registry):
|
for validator_index, _ in enumerate(state.validator_registry):
|
||||||
if get_effective_balance(state, validator_index) >= MAX_DEPOSIT * GWEI_PER_ETH:
|
if get_effective_balance(state, validator_index) >= MAX_DEPOSIT_AMOUNT:
|
||||||
activate_validator(state, validator_index, True)
|
activate_validator(state, validator_index, True)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
@ -1321,7 +1335,7 @@ def validate_proof_of_possession(state: BeaconState,
|
||||||
message=hash_tree_root(proof_of_possession_data),
|
message=hash_tree_root(proof_of_possession_data),
|
||||||
signature=signature_to_tuple(proof_of_possession),
|
signature=signature_to_tuple(proof_of_possession),
|
||||||
domain=get_domain(
|
domain=get_domain(
|
||||||
state.fork_data,
|
state.fork,
|
||||||
state.slot,
|
state.slot,
|
||||||
DOMAIN_DEPOSIT,
|
DOMAIN_DEPOSIT,
|
||||||
)
|
)
|
||||||
|
@ -1356,7 +1370,7 @@ def process_deposit(state: BeaconState,
|
||||||
|
|
||||||
if pubkey not in validator_pubkeys:
|
if pubkey not in validator_pubkeys:
|
||||||
# Add new validator
|
# Add new validator
|
||||||
validator = ValidatorRecord(
|
validator = Validator(
|
||||||
pubkey=pubkey,
|
pubkey=pubkey,
|
||||||
withdrawal_credentials=withdrawal_credentials,
|
withdrawal_credentials=withdrawal_credentials,
|
||||||
randao_commitment=randao_commitment,
|
randao_commitment=randao_commitment,
|
||||||
|
@ -1437,7 +1451,7 @@ def exit_validator(state: BeaconState, index: int) -> None:
|
||||||
def penalize_validator(state: BeaconState, index: int) -> None:
|
def penalize_validator(state: BeaconState, index: int) -> None:
|
||||||
exit_validator(state, index)
|
exit_validator(state, index)
|
||||||
validator = state.validator_registry[index]
|
validator = state.validator_registry[index]
|
||||||
state.latest_penalized_exit_balances[(state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH] += get_effective_balance(state, index)
|
state.latest_penalized_balances[(state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH] += get_effective_balance(state, index)
|
||||||
|
|
||||||
whistleblower_index = get_beacon_proposer_index(state, state.slot)
|
whistleblower_index = get_beacon_proposer_index(state, state.slot)
|
||||||
whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
|
whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
|
||||||
|
@ -1480,7 +1494,7 @@ Below are the processing steps that happen at every `block`.
|
||||||
|
|
||||||
* Let `block_without_signature_root` be the `hash_tree_root` of `block` where `block.signature` is set to `EMPTY_SIGNATURE`.
|
* Let `block_without_signature_root` be the `hash_tree_root` of `block` where `block.signature` is set to `EMPTY_SIGNATURE`.
|
||||||
* Let `proposal_root = hash_tree_root(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_without_signature_root))`.
|
* Let `proposal_root = hash_tree_root(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_without_signature_root))`.
|
||||||
* Verify that `bls_verify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, message=proposal_root, signature=signature_to_tuple(block.signature), domain=get_domain(state.fork_data, state.slot, DOMAIN_PROPOSAL))`.
|
* Verify that `bls_verify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, message=proposal_root, signature=signature_to_tuple(block.signature), domain=get_domain(state.fork, state.slot, DOMAIN_PROPOSAL))`.
|
||||||
|
|
||||||
### RANDAO
|
### RANDAO
|
||||||
|
|
||||||
|
@ -1491,10 +1505,10 @@ Below are the processing steps that happen at every `block`.
|
||||||
* Set `proposer.randao_commitment = block.randao_reveal`.
|
* Set `proposer.randao_commitment = block.randao_reveal`.
|
||||||
* Set `proposer.randao_layers = 0`.
|
* Set `proposer.randao_layers = 0`.
|
||||||
|
|
||||||
### Deposit root
|
### Eth1 data
|
||||||
|
|
||||||
* If `block.deposit_root` is `deposit_root_vote.deposit_root` for some `deposit_root_vote` in `state.deposit_root_votes`, set `deposit_root_vote.vote_count += 1`.
|
* If `block.eth1_data` equals `eth1_data_vote.eth1_data` for some `eth1_data_vote` in `state.eth1_data_votes`, set `eth1_data_vote.vote_count += 1`.
|
||||||
* Otherwise, append to `state.deposit_root_votes` a new `DepositRootVote(deposit_root=block.deposit_root, vote_count=1)`.
|
* Otherwise, append to `state.eth1_data_votes` a new `Eth1DataVote(eth1_data=block.eth1_data, vote_count=1)`.
|
||||||
|
|
||||||
### Operations
|
### Operations
|
||||||
|
|
||||||
|
@ -1509,8 +1523,8 @@ For each `proposer_slashing` in `block.body.proposer_slashings`:
|
||||||
* Verify that `proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard`.
|
* Verify that `proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard`.
|
||||||
* Verify that `proposer_slashing.proposal_data_1.block_root != proposer_slashing.proposal_data_2.block_root`.
|
* Verify that `proposer_slashing.proposal_data_1.block_root != proposer_slashing.proposal_data_2.block_root`.
|
||||||
* Verify that `proposer.penalized_slot > state.slot`.
|
* Verify that `proposer.penalized_slot > state.slot`.
|
||||||
* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_1), signature=signature_to_tuple(proposer_slashing.proposal_signature_1), domain=get_domain(state.fork_data, proposer_slashing.proposal_data_1.slot, DOMAIN_PROPOSAL))`.
|
* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_1), signature=signature_to_tuple(proposer_slashing.proposal_signature_1), domain=get_domain(state.fork, proposer_slashing.proposal_data_1.slot, DOMAIN_PROPOSAL))`.
|
||||||
* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_2), signature=signature_to_tuple(proposer_slashing.proposal_signature_2), domain=get_domain(state.fork_data, proposer_slashing.proposal_data_2.slot, DOMAIN_PROPOSAL))`.
|
* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_2), signature=signature_to_tuple(proposer_slashing.proposal_signature_2), domain=get_domain(state.fork, proposer_slashing.proposal_data_2.slot, DOMAIN_PROPOSAL))`.
|
||||||
* Run `penalize_validator(state, proposer_slashing.proposer_index)`.
|
* Run `penalize_validator(state, proposer_slashing.proposer_index)`.
|
||||||
|
|
||||||
#### Casper slashings
|
#### Casper slashings
|
||||||
|
@ -1542,11 +1556,11 @@ For each `attestation` in `block.body.attestations`:
|
||||||
* Verify that `attestation.data.justified_block_root` is equal to `get_block_root(state, attestation.data.justified_slot)`.
|
* Verify that `attestation.data.justified_block_root` is equal to `get_block_root(state, attestation.data.justified_slot)`.
|
||||||
* Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`.
|
* Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`.
|
||||||
* `aggregate_signature` verification:
|
* `aggregate_signature` verification:
|
||||||
* Let `participants = get_attestation_participants(state, attestation.data, attestation.participation_bitfield)`.
|
* Let `participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)`.
|
||||||
* Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`.
|
* Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`.
|
||||||
* Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationDataAndCustodyBit(attestation.data, False)), signature=signature_to_tuple(attestation.aggregate_signature), domain=get_domain(state.fork_data, attestation.data.slot, DOMAIN_ATTESTATION))`.
|
* Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationDataAndCustodyBit(attestation.data, False)), signature=signature_to_tuple(attestation.aggregate_signature), domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`.
|
||||||
* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`.
|
* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == 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`.
|
* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
|
||||||
|
|
||||||
#### Deposits
|
#### Deposits
|
||||||
|
|
||||||
|
@ -1558,7 +1572,7 @@ Verify that `len(block.body.deposits) <= MAX_DEPOSITS`.
|
||||||
For each `deposit` in `block.body.deposits`:
|
For each `deposit` in `block.body.deposits`:
|
||||||
|
|
||||||
* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be 8 bytes for `deposit_data.amount` followed by 8 bytes for `deposit_data.timestamp` and then the `DepositInput` bytes. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) of which the hash was placed into the Merkle tree.
|
* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be 8 bytes for `deposit_data.amount` followed by 8 bytes for `deposit_data.timestamp` and then the `DepositInput` bytes. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) of which the hash was placed into the Merkle tree.
|
||||||
* Verify that `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index, state.latest_deposit_root)` is `True`.
|
* Verify that `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index, state.latest_eth1_data.deposit_root)` is `True`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def verify_merkle_branch(leaf: Bytes32, branch: [Bytes32], depth: int, index: int, root: Bytes32) -> bool:
|
def verify_merkle_branch(leaf: Bytes32, branch: [Bytes32], depth: int, index: int, root: Bytes32) -> bool:
|
||||||
|
@ -1594,7 +1608,7 @@ For each `exit` in `block.body.exits`:
|
||||||
* Let `validator = state.validator_registry[exit.validator_index]`.
|
* Let `validator = state.validator_registry[exit.validator_index]`.
|
||||||
* Verify that `validator.exit_slot > state.slot + ENTRY_EXIT_DELAY`.
|
* Verify that `validator.exit_slot > state.slot + ENTRY_EXIT_DELAY`.
|
||||||
* Verify that `state.slot >= exit.slot`.
|
* Verify that `state.slot >= exit.slot`.
|
||||||
* Verify that `bls_verify(pubkey=validator.pubkey, message=ZERO_HASH, signature=signature_to_tuple(exit.signature), domain=get_domain(state.fork_data, exit.slot, DOMAIN_EXIT))`.
|
* Verify that `bls_verify(pubkey=validator.pubkey, message=ZERO_HASH, signature=signature_to_tuple(exit.signature), domain=get_domain(state.fork, exit.slot, DOMAIN_EXIT))`.
|
||||||
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
||||||
|
|
||||||
#### Custody
|
#### Custody
|
||||||
|
@ -1617,25 +1631,25 @@ All [validators](#dfn-validator):
|
||||||
* Let `current_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 `current_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`.)
|
||||||
* Validators justifying the epoch boundary block at the start of the current epoch:
|
* Validators justifying the epoch boundary block at the start of the current epoch:
|
||||||
* Let `current_epoch_boundary_attestations = [a for a in current_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`.
|
* Let `current_epoch_boundary_attestations = [a for a in current_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`.
|
||||||
* Let `current_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 current_epoch_boundary_attestations]`.
|
* Let `current_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in current_epoch_boundary_attestations]`.
|
||||||
* Let `current_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in current_epoch_boundary_attester_indices])`.
|
* Let `current_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in current_epoch_boundary_attester_indices])`.
|
||||||
|
|
||||||
[Validators](#dfn-Validator) attesting during the previous epoch:
|
[Validators](#dfn-Validator) attesting during the previous epoch:
|
||||||
|
|
||||||
* Validators that made an attestation during the previous epoch:
|
* Validators that made an attestation during 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_attestations = [a for a in state.latest_attestations if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]`.
|
||||||
* Let `previous_epoch_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_attestations]`.
|
* Let `previous_epoch_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_attestations]`.
|
||||||
* Validators targeting the previous justified slot:
|
* Validators targeting the previous justified slot:
|
||||||
* Let `previous_epoch_justified_attestations = [a for a in current_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`.
|
* Let `previous_epoch_justified_attestations = [a for a in current_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`.
|
||||||
* Let `previous_epoch_justified_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_justified_attestations]`.
|
* Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_justified_attestations]`.
|
||||||
* Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_justified_attester_indices])`.
|
* Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_justified_attester_indices])`.
|
||||||
* Validators justifying the epoch boundary block at the start of the previous epoch:
|
* Validators justifying the epoch boundary block at the start of the previous epoch:
|
||||||
* Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`.
|
* Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`.
|
||||||
* 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_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_boundary_attestations]`.
|
||||||
* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_boundary_attester_indices])`.
|
* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_boundary_attester_indices])`.
|
||||||
* Validators attesting to the expected beacon chain head during the previous epoch:
|
* Validators attesting to the expected beacon chain head during the previous epoch:
|
||||||
* Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`.
|
* Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`.
|
||||||
* Let `previous_epoch_head_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_head_attestations]`.
|
* Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_head_attestations]`.
|
||||||
* Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_head_attester_indices])`.
|
* Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_head_attester_indices])`.
|
||||||
|
|
||||||
**Note**: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `current_epoch_boundary_attesting_balance` during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety.
|
**Note**: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `current_epoch_boundary_attesting_balance` during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety.
|
||||||
|
@ -1643,7 +1657,7 @@ All [validators](#dfn-validator):
|
||||||
For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `crosslink_committee_at_slot = get_crosslink_committees_at_slot(slot)`. For every `(crosslink_committee, shard)` in `crosslink_committee_at_slot`, compute:
|
For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `crosslink_committee_at_slot = get_crosslink_committees_at_slot(slot)`. For every `(crosslink_committee, shard)` in `crosslink_committee_at_slot`, compute:
|
||||||
|
|
||||||
* Let `shard_block_root` be `state.latest_crosslinks[shard].shard_block_root`
|
* Let `shard_block_root` be `state.latest_crosslinks[shard].shard_block_root`
|
||||||
* Let `attesting_validator_indices(crosslink_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.shard == shard and a.shard_block_root == shard_block_root]`.
|
* Let `attesting_validator_indices(crosslink_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.shard == shard and a.shard_block_root == shard_block_root]`.
|
||||||
* Let `winning_root(crosslink_committee)` be equal to the value of `shard_block_root` such that `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values).
|
* Let `winning_root(crosslink_committee)` be equal to the value of `shard_block_root` such that `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values).
|
||||||
* Let `attesting_validators(crosslink_committee)` be equal to `attesting_validator_indices(crosslink_committee, winning_root(crosslink_committee))` for convenience.
|
* Let `attesting_validators(crosslink_committee)` be equal to `attesting_validator_indices(crosslink_committee, winning_root(crosslink_committee))` for convenience.
|
||||||
* Let `total_attesting_balance(crosslink_committee) = sum([get_effective_balance(state, i) for i in attesting_validators(crosslink_committee)])`.
|
* Let `total_attesting_balance(crosslink_committee) = sum([get_effective_balance(state, i) for i in attesting_validators(crosslink_committee)])`.
|
||||||
|
@ -1651,15 +1665,15 @@ For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `cross
|
||||||
|
|
||||||
Define the following helpers to process attestation inclusion rewards and inclusion distance reward/penalty. For every attestation `a` in `previous_epoch_attestations`:
|
Define the following helpers to process attestation inclusion rewards and inclusion distance reward/penalty. For every attestation `a` in `previous_epoch_attestations`:
|
||||||
|
|
||||||
* Let `inclusion_slot(state, index) = a.slot_included` for the attestation `a` where `index` is in `get_attestation_participants(state, a.data, a.participation_bitfield)`.
|
* Let `inclusion_slot(state, index) = a.slot_included` for the attestation `a` where `index` is in `get_attestation_participants(state, a.data, a.aggregation_bitfield)`.
|
||||||
* Let `inclusion_distance(state, index) = a.slot_included - a.data.slot` where `a` is the above attestation.
|
* Let `inclusion_distance(state, index) = a.slot_included - a.data.slot` where `a` is the above attestation.
|
||||||
|
|
||||||
### Deposit roots
|
### Eth1 data
|
||||||
|
|
||||||
If `state.slot % DEPOSIT_ROOT_VOTING_PERIOD == 0`:
|
If `state.slot % ETH1_DATA_VOTING_PERIOD == 0`:
|
||||||
|
|
||||||
* Set `state.latest_deposit_root = deposit_root_vote.deposit_root` if `deposit_root_vote.vote_count * 2 > DEPOSIT_ROOT_VOTING_PERIOD` for some `deposit_root_vote` in `state.deposit_root_votes`.
|
* Set `state.latest_eth1_data = eth1_data_vote.data` if `eth1_data_vote.vote_count * 2 > ETH1_DATA_VOTING_PERIOD` for some `eth1_data_vote` in `state.eth1_data_votes`.
|
||||||
* Set `state.deposit_root_votes = []`.
|
* Set `state.eth1_data_votes = []`.
|
||||||
|
|
||||||
### Justification
|
### Justification
|
||||||
|
|
||||||
|
@ -1678,13 +1692,13 @@ Set `state.finalized_slot = state.previous_justified_slot` if any of the followi
|
||||||
|
|
||||||
For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `crosslink_committee_at_slot = get_crosslink_committees_at_slot(slot)`. For every `(crosslink_committee, shard)` in `crosslink_committee_at_slot`, compute:
|
For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `crosslink_committee_at_slot = get_crosslink_committees_at_slot(slot)`. For every `(crosslink_committee, shard)` in `crosslink_committee_at_slot`, compute:
|
||||||
|
|
||||||
* Set `state.latest_crosslinks[shard] = CrosslinkRecord(slot=state.slot, shard_block_root=winning_root(crosslink_committee))` if `3 * total_attesting_balance(crosslink_committee) >= 2 * total_balance(crosslink_committee)`.
|
* Set `state.latest_crosslinks[shard] = Crosslink(slot=state.slot, shard_block_root=winning_root(crosslink_committee))` if `3 * total_attesting_balance(crosslink_committee) >= 2 * total_balance(crosslink_committee)`.
|
||||||
|
|
||||||
### Rewards and penalties
|
### Rewards and penalties
|
||||||
|
|
||||||
First, we define some additional helpers:
|
First, we define some additional helpers:
|
||||||
|
|
||||||
* Let `base_reward_quotient = BASE_REWARD_QUOTIENT * integer_squareroot(total_balance // GWEI_PER_ETH)`.
|
* Let `base_reward_quotient = integer_squareroot(total_balance) // BASE_REWARD_QUOTIENT`.
|
||||||
* Let `base_reward(state, index) = get_effective_balance(state, index) // base_reward_quotient // 5` for any validator with the given `index`.
|
* Let `base_reward(state, index) = get_effective_balance(state, index) // base_reward_quotient // 5` for any validator with the given `index`.
|
||||||
* Let `inactivity_penalty(state, index, epochs_since_finality) = base_reward(state, index) + get_effective_balance(state, index) * epochs_since_finality // INACTIVITY_PENALTY_QUOTIENT // 2` for any validator with the given `index`.
|
* Let `inactivity_penalty(state, index, epochs_since_finality) = base_reward(state, index) + get_effective_balance(state, index) * epochs_since_finality // INACTIVITY_PENALTY_QUOTIENT // 2` for any validator with the given `index`.
|
||||||
|
|
||||||
|
@ -1738,7 +1752,7 @@ def process_ejections(state: BeaconState) -> None:
|
||||||
and eject active validators with balance below ``EJECTION_BALANCE``.
|
and eject active validators with balance below ``EJECTION_BALANCE``.
|
||||||
"""
|
"""
|
||||||
for index in get_active_validator_indices(state.validator_registry, state.slot):
|
for index in get_active_validator_indices(state.validator_registry, state.slot):
|
||||||
if state.validator_balances[index] < EJECTION_BALANCE * GWEI_PER_ETH:
|
if state.validator_balances[index] < EJECTION_BALANCE:
|
||||||
exit_validator(state, index)
|
exit_validator(state, index)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1746,8 +1760,8 @@ def process_ejections(state: BeaconState) -> None:
|
||||||
|
|
||||||
If the following are satisfied:
|
If the following are satisfied:
|
||||||
|
|
||||||
* `state.finalized_slot > state.validator_registry_latest_change_slot`
|
* `state.finalized_slot > state.validator_registry_update_slot`
|
||||||
* `state.latest_crosslinks[shard].slot > state.validator_registry_latest_change_slot` for every shard number `shard` in `[(state.current_epoch_start_shard + i) % SHARD_COUNT for i in range(get_current_epoch_committee_count_per_slot(state) * EPOCH_LENGTH)]` (that is, for every shard in the current committees)
|
* `state.latest_crosslinks[shard].slot > state.validator_registry_update_slot` for every shard number `shard` in `[(state.current_epoch_start_shard + i) % SHARD_COUNT for i in range(get_current_epoch_committee_count_per_slot(state) * EPOCH_LENGTH)]` (that is, for every shard in the current committees)
|
||||||
|
|
||||||
update the validator registry and associated fields by running
|
update the validator registry and associated fields by running
|
||||||
|
|
||||||
|
@ -1764,14 +1778,14 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
|
|
||||||
# The maximum balance churn in Gwei (for deposits and exits separately)
|
# The maximum balance churn in Gwei (for deposits and exits separately)
|
||||||
max_balance_churn = max(
|
max_balance_churn = max(
|
||||||
MAX_DEPOSIT * GWEI_PER_ETH,
|
MAX_DEPOSIT_AMOUNT,
|
||||||
total_balance // (2 * MAX_BALANCE_CHURN_QUOTIENT)
|
total_balance // (2 * MAX_BALANCE_CHURN_QUOTIENT)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Activate validators within the allowable balance churn
|
# Activate validators within the allowable balance churn
|
||||||
balance_churn = 0
|
balance_churn = 0
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if validator.activation_slot > state.slot + ENTRY_EXIT_DELAY and state.validator_balances[index] >= MAX_DEPOSIT * GWEI_PER_ETH:
|
if validator.activation_slot > state.slot + ENTRY_EXIT_DELAY and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(state, index)
|
balance_churn += get_effective_balance(state, index)
|
||||||
if balance_churn > max_balance_churn:
|
if balance_churn > max_balance_churn:
|
||||||
|
@ -1792,7 +1806,7 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
# Exit validator
|
# Exit validator
|
||||||
exit_validator(state, index)
|
exit_validator(state, index)
|
||||||
|
|
||||||
state.validator_registry_latest_change_slot = state.slot
|
state.validator_registry_update_slot = state.slot
|
||||||
```
|
```
|
||||||
|
|
||||||
and perform the following updates:
|
and perform the following updates:
|
||||||
|
@ -1808,7 +1822,7 @@ If a validator registry update does _not_ happen do the following:
|
||||||
|
|
||||||
* Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot`
|
* Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot`
|
||||||
* Set `state.previous_epoch_start_shard = state.current_epoch_start_shard`
|
* Set `state.previous_epoch_start_shard = state.current_epoch_start_shard`
|
||||||
* Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_latest_change_slot) // EPOCH_LENGTH`.
|
* Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_update_slot) // EPOCH_LENGTH`.
|
||||||
* If `epochs_since_last_registry_change` is an exact power of 2, set `state.current_epoch_calculation_slot = state.slot` and `state.current_epoch_randao_mix = state.latest_randao_mixes[(state.current_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]`. Note that `state.current_epoch_start_shard` is left unchanged.
|
* If `epochs_since_last_registry_change` is an exact power of 2, set `state.current_epoch_calculation_slot = state.slot` and `state.current_epoch_randao_mix = state.latest_randao_mixes[(state.current_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]`. Note that `state.current_epoch_start_shard` is left unchanged.
|
||||||
|
|
||||||
Regardless of whether or not a validator set change happens, run the following:
|
Regardless of whether or not a validator set change happens, run the following:
|
||||||
|
@ -1823,8 +1837,8 @@ def process_penalties_and_exits(state: BeaconState) -> None:
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if (state.slot // EPOCH_LENGTH) == (validator.penalized_slot // EPOCH_LENGTH) + LATEST_PENALIZED_EXIT_LENGTH // 2:
|
if (state.slot // EPOCH_LENGTH) == (validator.penalized_slot // EPOCH_LENGTH) + LATEST_PENALIZED_EXIT_LENGTH // 2:
|
||||||
e = (state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH
|
e = (state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH
|
||||||
total_at_start = state.latest_penalized_exit_balances[(e + 1) % LATEST_PENALIZED_EXIT_LENGTH]
|
total_at_start = state.latest_penalized_balances[(e + 1) % LATEST_PENALIZED_EXIT_LENGTH]
|
||||||
total_at_end = state.latest_penalized_exit_balances[e]
|
total_at_end = state.latest_penalized_balances[e]
|
||||||
total_penalties = total_at_end - total_at_start
|
total_penalties = total_at_end - total_at_start
|
||||||
penalty = get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance
|
penalty = get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance
|
||||||
state.validator_balances[index] -= penalty
|
state.validator_balances[index] -= penalty
|
||||||
|
@ -1850,7 +1864,7 @@ def process_penalties_and_exits(state: BeaconState) -> None:
|
||||||
|
|
||||||
### Final updates
|
### Final updates
|
||||||
|
|
||||||
* Let `e = state.slot // EPOCH_LENGTH`. Set `state.latest_penalized_exit_balances[(e+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_exit_balances[e % LATEST_PENALIZED_EXIT_LENGTH]`
|
* Let `e = state.slot // EPOCH_LENGTH`. Set `state.latest_penalized_balances[(e+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[e % LATEST_PENALIZED_EXIT_LENGTH]`
|
||||||
* Remove any `attestation` in `state.latest_attestations` such that `attestation.data.slot < state.slot - EPOCH_LENGTH`.
|
* Remove any `attestation` in `state.latest_attestations` such that `attestation.data.slot < state.slot - EPOCH_LENGTH`.
|
||||||
|
|
||||||
## State root processing
|
## State root processing
|
||||||
|
|
|
@ -15,20 +15,24 @@ deserializing objects and data types.
|
||||||
+ [Serialize/Encode](#serializeencode)
|
+ [Serialize/Encode](#serializeencode)
|
||||||
- [uint](#uint)
|
- [uint](#uint)
|
||||||
- [Bool](#bool)
|
- [Bool](#bool)
|
||||||
- [Address](#address)
|
|
||||||
- [Hash](#hash)
|
|
||||||
- [Bytes](#bytes)
|
- [Bytes](#bytes)
|
||||||
|
- [bytesN](#bytesn)
|
||||||
|
- [bytes](#bytes-1)
|
||||||
- [List/Vectors](#listvectors)
|
- [List/Vectors](#listvectors)
|
||||||
- [Container](#container)
|
- [Container](#container)
|
||||||
+ [Deserialize/Decode](#deserializedecode)
|
+ [Deserialize/Decode](#deserializedecode)
|
||||||
- [uint](#uint-1)
|
- [uint](#uint-1)
|
||||||
- [Bool](#bool-1)
|
- [Bool](#bool-1)
|
||||||
- [Address](#address-1)
|
- [Bytes](#bytes-2)
|
||||||
- [Hash](#hash-1)
|
- [bytesN](#bytesn-1)
|
||||||
- [Bytes](#bytes-1)
|
- [bytes](#bytes-1)
|
||||||
- [List/Vectors](#listvectors-1)
|
- [List/Vectors](#listvectors-1)
|
||||||
- [Container](#container-1)
|
- [Container](#container-1)
|
||||||
+ [Tree Hash](#tree-hash)
|
+ [Tree Hash](#tree-hash)
|
||||||
|
- [`uint8`..`uint256`, `bool`, `bytes1`..`bytes32`](#uint8uint256-bool-bytes1bytes32)
|
||||||
|
- [`uint264`..`uintN`, `bytes`, `bytes33`..`bytesN`](#uint264uintn-bytes-bytes33bytesn)
|
||||||
|
- [List/Vectors](#listvectors-2)
|
||||||
|
- [Container](#container-2)
|
||||||
* [Implementations](#implementations)
|
* [Implementations](#implementations)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
@ -58,7 +62,6 @@ overhead.
|
||||||
| `LENGTH_BYTES` | 4 | Number of bytes used for the length added before a variable-length serialized object. |
|
| `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 chunk size of the Merkle tree leaf. |
|
| `SSZ_CHUNK_SIZE` | 128 | Number of bytes for the chunk size of the Merkle tree leaf. |
|
||||||
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
### Serialize/Encode
|
### Serialize/Encode
|
||||||
|
@ -97,32 +100,18 @@ assert(value in (True, False))
|
||||||
return b'\x01' if value is True else b'\x00'
|
return b'\x01' if value is True else b'\x00'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Bytes
|
||||||
|
|
||||||
#### Address
|
| Bytes Type | Usage |
|
||||||
|
|:---------:|:------------------------------------|
|
||||||
The `address` should already come as a hash/byte format. Ensure that length is **20**.
|
| `bytesN` | Explicit length `N` bytes data. |
|
||||||
|
| `bytes` | Bytes data with arbitrary length. |
|
||||||
| Check to perform | Code |
|
|
||||||
|:-----------------------|:---------------------|
|
|
||||||
| Length is correct (20) | ``len(value) == 20`` |
|
|
||||||
|
|
||||||
```python
|
|
||||||
assert( len(value) == 20 )
|
|
||||||
return value
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Hash
|
|
||||||
|
|
||||||
| Hash Type | Usage |
|
|
||||||
|:---------:|:------------------------------------------------|
|
|
||||||
| `hashN` | Hash of arbitrary byte length `N`. |
|
|
||||||
|
|
||||||
|
##### bytesN
|
||||||
|
|
||||||
| Checks to perform | Code |
|
| Checks to perform | Code |
|
||||||
|:---------------------------------------|:---------------------|
|
|:---------------------------------------|:---------------------|
|
||||||
| Length in bytes is correct for `hashN` | ``len(value) == N`` |
|
| Length in bytes is correct for `bytesN` | ``len(value) == N`` |
|
||||||
|
|
||||||
##### hashN
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
assert(len(value) == N)
|
assert(len(value) == N)
|
||||||
|
@ -130,8 +119,7 @@ assert(len(value) == N)
|
||||||
return value
|
return value
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Bytes
|
##### bytes
|
||||||
|
|
||||||
For general `bytes` type:
|
For general `bytes` type:
|
||||||
1. Get the length/number of bytes; Encode into a `4-byte` integer.
|
1. Get the length/number of bytes; Encode into a `4-byte` integer.
|
||||||
2. Append the value to the length and return: ``[ length_bytes ] + [ value_bytes ]``
|
2. Append the value to the length and return: ``[ length_bytes ] + [ value_bytes ]``
|
||||||
|
@ -263,19 +251,9 @@ assert rawbytes in (b'\x00', b'\x01')
|
||||||
return True if rawbytes == b'\x01' else False
|
return True if rawbytes == b'\x01' else False
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Address
|
#### Bytes
|
||||||
|
|
||||||
Return the 20-byte deserialized address.
|
##### bytesN
|
||||||
|
|
||||||
```python
|
|
||||||
assert(len(rawbytes) >= current_index + 20)
|
|
||||||
new_index = current_index + 20
|
|
||||||
return rawbytes[current_index:current_index+20], new_index
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Hash
|
|
||||||
|
|
||||||
##### hashN
|
|
||||||
|
|
||||||
Return the `N` bytes.
|
Return the `N` bytes.
|
||||||
|
|
||||||
|
@ -285,7 +263,7 @@ new_index = current_index + N
|
||||||
return rawbytes[current_index:current_index+N], new_index
|
return rawbytes[current_index:current_index+N], new_index
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Bytes
|
##### bytes
|
||||||
|
|
||||||
Get the length of the bytes, return the bytes.
|
Get the length of the bytes, return the bytes.
|
||||||
|
|
||||||
|
@ -394,11 +372,11 @@ The below `hash_tree_root` algorithm is defined recursively in the case of lists
|
||||||
|
|
||||||
Refer to [the helper function `hash`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#hash) of Phase 0 of the [Eth2.0 specs](https://github.com/ethereum/eth2.0-specs) for a definition of the hash function used below, `hash(x)`.
|
Refer to [the helper function `hash`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#hash) of Phase 0 of the [Eth2.0 specs](https://github.com/ethereum/eth2.0-specs) for a definition of the hash function used below, `hash(x)`.
|
||||||
|
|
||||||
#### `uint8`..`uint256`, `bool`, `address`, `hash1`..`hash32`
|
#### `uint8`..`uint256`, `bool`, `bytes1`..`bytes32`
|
||||||
|
|
||||||
Return the serialization of the value.
|
Return the serialization of the value.
|
||||||
|
|
||||||
#### `uint264`..`uintN`, `bytes`, `hash33`..`hashN`
|
#### `uint264`..`uintN`, `bytes`, `bytes33`..`bytesN`
|
||||||
|
|
||||||
Return the hash of the serialization of the value.
|
Return the hash of the serialization of the value.
|
||||||
|
|
||||||
|
@ -443,7 +421,6 @@ return merkle_hash([hash_tree_root(item) for item in value])
|
||||||
|
|
||||||
Where the inner `hash_tree_root` is a recursive application of the tree-hashing function (returning less than 32 bytes for short single values).
|
Where the inner `hash_tree_root` is a recursive application of the tree-hashing function (returning less than 32 bytes for short single values).
|
||||||
|
|
||||||
|
|
||||||
#### Container
|
#### Container
|
||||||
|
|
||||||
Recursively tree hash the values in the container in the same order as the fields, and return the hash of the concatenation of the results.
|
Recursively tree hash the values in the container in the same order as the fields, and return the hash of the concatenation of the results.
|
||||||
|
@ -452,12 +429,11 @@ Recursively tree hash the values in the container in the same order as the field
|
||||||
return hash(b''.join([hash_tree_root(getattr(x, field)) for field in value.fields]))
|
return hash(b''.join([hash_tree_root(getattr(x, field)) for field in value.fields]))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Implementations
|
## Implementations
|
||||||
|
|
||||||
| Language | Implementation | Description |
|
| Language | Implementation | Description |
|
||||||
|:--------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|
|
|:--------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|
|
||||||
| Python | [ https://github.com/ethereum/beacon_chain/blob/master/ssz/ssz.py ](https://github.com/ethereum/beacon_chain/blob/master/ssz/ssz.py) | Beacon chain reference implementation written in Python. |
|
| Python | [ https://github.com/ethereum/py-ssz ](https://github.com/ethereum/py-ssz) | Python implementation of SSZ |
|
||||||
| Rust | [ https://github.com/sigp/lighthouse/tree/master/beacon_chain/utils/ssz ](https://github.com/sigp/lighthouse/tree/master/beacon_chain/utils/ssz) | Lighthouse (Rust Ethereum 2.0 Node) maintained SSZ. |
|
| Rust | [ https://github.com/sigp/lighthouse/tree/master/beacon_chain/utils/ssz ](https://github.com/sigp/lighthouse/tree/master/beacon_chain/utils/ssz) | Lighthouse (Rust Ethereum 2.0 Node) maintained SSZ. |
|
||||||
| Nim | [ https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim ](https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim) | Nim Implementation maintained SSZ. |
|
| Nim | [ https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim ](https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim) | Nim Implementation maintained SSZ. |
|
||||||
| Rust | [ https://github.com/paritytech/shasper/tree/master/util/ssz ](https://github.com/paritytech/shasper/tree/master/util/ssz) | Shasper implementation of SSZ maintained by ParityTech. |
|
| Rust | [ https://github.com/paritytech/shasper/tree/master/util/ssz ](https://github.com/paritytech/shasper/tree/master/util/ssz) | Shasper implementation of SSZ maintained by ParityTech. |
|
||||||
|
|
Loading…
Reference in New Issue