Skip to content

Commit

Permalink
Merge pull request #1820 from ethereum/v012x
Browse files Browse the repository at this point in the history
v012x to dev
  • Loading branch information
djrtwo authored May 19, 2020
2 parents 6655382 + dbb1ee6 commit 4d6b99b
Show file tree
Hide file tree
Showing 53 changed files with 1,840 additions and 1,313 deletions.
14 changes: 6 additions & 8 deletions configs/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ EPOCHS_PER_ETH1_VOTING_PERIOD: 32
SLOTS_PER_HISTORICAL_ROOT: 8192
# 2**8 (= 256) epochs ~27 hours
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# 2**11 (= 2,048) epochs 9 days
PERSISTENT_COMMITTEE_PERIOD: 2048
# 2**8 (= 256) epochs ~27 hours
SHARD_COMMITTEE_PERIOD: 256
# 2**6 (= 64) epochs ~7 hours
MAX_EPOCHS_PER_CROSSLINK: 64
# 2**2 (= 4) epochs 25.6 minutes
Expand All @@ -122,8 +122,8 @@ BASE_REWARD_FACTOR: 64
WHISTLEBLOWER_REWARD_QUOTIENT: 512
# 2**3 (= 8)
PROPOSER_REWARD_QUOTIENT: 8
# 2**25 (= 33,554,432)
INACTIVITY_PENALTY_QUOTIENT: 33554432
# 2**24 (= 16,777,216)
INACTIVITY_PENALTY_QUOTIENT: 16777216
# 2**5 (= 32)
MIN_SLASHING_PENALTY_QUOTIENT: 32

Expand All @@ -132,8 +132,8 @@ MIN_SLASHING_PENALTY_QUOTIENT: 32
# ---------------------------------------------------------------
# 2**4 (= 16)
MAX_PROPOSER_SLASHINGS: 16
# 2**0 (= 1)
MAX_ATTESTER_SLASHINGS: 1
# 2**1 (= 2)
MAX_ATTESTER_SLASHINGS: 2
# 2**7 (= 128)
MAX_ATTESTATIONS: 128
# 2**4 (= 16)
Expand Down Expand Up @@ -175,8 +175,6 @@ ONLINE_PERIOD: 8
LIGHT_CLIENT_COMMITTEE_SIZE: 128
# 2**8 (= 256) | epochs | ~27 hours
LIGHT_CLIENT_COMMITTEE_PERIOD: 256
# 2**8 (= 256) | epochs | ~27 hours
SHARD_COMMITTEE_PERIOD: 256
# 2**18 (= 262,144)
SHARD_BLOCK_CHUNK_SIZE: 262144
# 2**2 (= 4)
Expand Down
14 changes: 6 additions & 8 deletions configs/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ MIN_SEED_LOOKAHEAD: 1
# 2**2 (= 4) epochs
MAX_SEED_LOOKAHEAD: 4
# [customized] higher frequency new deposits from eth1 for testing
EPOCHS_PER_ETH1_VOTING_PERIOD: 2
EPOCHS_PER_ETH1_VOTING_PERIOD: 4
# [customized] smaller state
SLOTS_PER_HISTORICAL_ROOT: 64
# 2**8 (= 256) epochs
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# [customized] higher frequency of committee turnover and faster time to acceptable voluntary exit
PERSISTENT_COMMITTEE_PERIOD: 128
SHARD_COMMITTEE_PERIOD: 64
# [customized] fast catchup crosslinks
MAX_EPOCHS_PER_CROSSLINK: 4
# 2**2 (= 4) epochs
Expand All @@ -122,8 +122,8 @@ BASE_REWARD_FACTOR: 64
WHISTLEBLOWER_REWARD_QUOTIENT: 512
# 2**3 (= 8)
PROPOSER_REWARD_QUOTIENT: 8
# 2**25 (= 33,554,432)
INACTIVITY_PENALTY_QUOTIENT: 33554432
# 2**24 (= 16,777,216)
INACTIVITY_PENALTY_QUOTIENT: 16777216
# 2**5 (= 32)
MIN_SLASHING_PENALTY_QUOTIENT: 32

Expand All @@ -132,8 +132,8 @@ MIN_SLASHING_PENALTY_QUOTIENT: 32
# ---------------------------------------------------------------
# 2**4 (= 16)
MAX_PROPOSER_SLASHINGS: 16
# 2**0 (= 1)
MAX_ATTESTER_SLASHINGS: 1
# 2**1 (= 2)
MAX_ATTESTER_SLASHINGS: 2
# 2**7 (= 128)
MAX_ATTESTATIONS: 128
# 2**4 (= 16)
Expand Down Expand Up @@ -178,8 +178,6 @@ ONLINE_PERIOD: 8
LIGHT_CLIENT_COMMITTEE_SIZE: 128
# 2**8 (= 256) | epochs
LIGHT_CLIENT_COMMITTEE_PERIOD: 256
# 2**8 (= 256) | epochs
SHARD_COMMITTEE_PERIOD: 256
# 2**18 (= 262,144)
SHARD_BLOCK_CHUNK_SIZE: 262144
# 2**2 (= 4)
Expand Down
12 changes: 8 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def get_spec(file_name: str) -> SpecObject:
PHASE1_IMPORTS = '''from eth2spec.phase0 import spec as phase0
from eth2spec.config.config_util import apply_constants_config
from typing import (
Any, Dict, Set, Sequence, NewType, Tuple, TypeVar, Callable
Any, Dict, Set, Sequence, NewType, Tuple, TypeVar, Callable, Optional
)
from dataclasses import (
Expand Down Expand Up @@ -146,8 +146,11 @@ def ceillog2(x: uint64) -> int:
hash_cache: Dict[bytes, Bytes32] = {}
def get_eth1_data(distance: uint64) -> Bytes32:
return hash(distance)
def get_eth1_data(block: Eth1Block) -> Eth1Data:
"""
A stub function return mocking Eth1Data.
"""
return Eth1Data(block_hash=hash_tree_root(block))
def hash(x: bytes) -> Bytes32: # type: ignore
Expand Down Expand Up @@ -373,6 +376,7 @@ def finalize_options(self):
self.md_doc_paths = """
specs/phase0/beacon-chain.md
specs/phase0/fork-choice.md
specs/phase0/validator.md
specs/phase1/custody-game.md
specs/phase1/beacon-chain.md
specs/phase1/shard-transition.md
Expand Down Expand Up @@ -497,7 +501,7 @@ def run(self):
"eth-utils>=1.3.0,<2",
"eth-typing>=2.1.0,<3.0.0",
"pycryptodome==3.9.4",
"py_ecc==2.0.0",
"py_ecc==4.0.0",
"dataclasses==0.6",
"remerkleable==0.1.13",
"ruamel.yaml==0.16.5",
Expand Down
54 changes: 27 additions & 27 deletions specs/phase0/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
- [`DepositMessage`](#depositmessage)
- [`DepositData`](#depositdata)
- [`BeaconBlockHeader`](#beaconblockheader)
- [`SigningRoot`](#signingroot)
- [`SigningData`](#signingdata)
- [Beacon operations](#beacon-operations)
- [`ProposerSlashing`](#proposerslashing)
- [`AttesterSlashing`](#attesterslashing)
Expand Down Expand Up @@ -195,7 +195,6 @@ The following values are (non-configurable) constants used throughout the specif
| `HYSTERESIS_DOWNWARD_MULTIPLIER` | `1` |
| `HYSTERESIS_UPWARD_MULTIPLIER` | `5` |


- For the safety of committees, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](http://web.archive.org/web/20190504131341/https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)

### Gwei values
Expand Down Expand Up @@ -228,7 +227,8 @@ The following values are (non-configurable) constants used throughout the specif
| `EPOCHS_PER_ETH1_VOTING_PERIOD` | `2**5` (= 32) | epochs | ~3.4 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~27 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
| `SHARD_COMMITTEE_PERIOD` | `Epoch(2**8)` (= 256) | epochs | ~27 hours |


### State list lengths

Expand All @@ -246,17 +246,17 @@ The following values are (non-configurable) constants used throughout the specif
| `BASE_REWARD_FACTOR` | `2**6` (= 64) |
| `WHISTLEBLOWER_REWARD_QUOTIENT` | `2**9` (= 512) |
| `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) |
| `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) |
| `INACTIVITY_PENALTY_QUOTIENT` | `2**24` (= 16,777,216) |
| `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) |

- The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (about 18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating validators to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline validators after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)`; so after `INVERSE_SQRT_E_DROP_TIME` epochs, it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
- The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12` epochs (about 18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating validators to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline validators after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)`; so after `INVERSE_SQRT_E_DROP_TIME` epochs, it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.

### Max operations per block

| Name | Value |
| - | - |
| `MAX_PROPOSER_SLASHINGS` | `2**4` (= 16) |
| `MAX_ATTESTER_SLASHINGS` | `2**0` (= 1) |
| `MAX_ATTESTER_SLASHINGS` | `2**1` (= 2) |
| `MAX_ATTESTATIONS` | `2**7` (= 128) |
| `MAX_DEPOSITS` | `2**4` (= 16) |
| `MAX_VOLUNTARY_EXITS` | `2**4` (= 16) |
Expand All @@ -273,7 +273,6 @@ The following values are (non-configurable) constants used throughout the specif
| `DOMAIN_SELECTION_PROOF` | `DomainType('0x05000000')` |
| `DOMAIN_AGGREGATE_AND_PROOF` | `DomainType('0x06000000')` |


## Containers

The following types are [SimpleSerialize (SSZ)](../../ssz/simple-serialize.md) containers.
Expand Down Expand Up @@ -403,10 +402,10 @@ class BeaconBlockHeader(Container):
body_root: Root
```

#### `SigningRoot`
#### `SigningData`

```python
class SigningRoot(Container):
class SigningData(Container):
object_root: Root
domain: Domain
```
Expand Down Expand Up @@ -608,16 +607,18 @@ def bytes_to_int(data: bytes) -> uint64:

#### BLS Signatures

Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00). Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuite which implements the following interfaces:
Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification draft-irtf-cfrg-bls-signature-02](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-02) but uses [Hashing to Elliptic Curves - draft-irtf-cfrg-hash-to-curve-07](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-07) instead of draft-irtf-cfrg-hash-to-curve-06. Specifically, eth2 uses the `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_` ciphersuite which implements the following interfaces:

- `def Sign(SK: int, message: Bytes) -> BLSSignature`
- `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool`
- `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature`
- `def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool`
- `def AggregateVerify(pairs: Sequence[PK: BLSPubkey, message: Bytes], signature: BLSSignature) -> bool`
- `def AggregateVerify(PKs: Sequence[BLSPubkey], messages: Sequence[Bytes], signature: BLSSignature) -> bool`

Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used.

*Note*: The non-standard configuration of the BLS and hash to curve specs is temporary and will be resolved once IETF releases BLS spec draft 3.

### Predicates

#### `is_active_validator`
Expand Down Expand Up @@ -688,11 +689,11 @@ def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationDa
```python
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
Check if ``indexed_attestation`` has sorted and unique indices and a valid aggregate signature.
Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature.
"""
# Verify indices are sorted and unique
indices = indexed_attestation.attesting_indices
if not indices == sorted(set(indices)):
if len(indices) == 0 or not indices == sorted(set(indices)):
return False
# Verify aggregate signature
pubkeys = [state.validators[i].pubkey for i in indices]
Expand Down Expand Up @@ -722,24 +723,24 @@ def is_valid_merkle_branch(leaf: Bytes32, branch: Sequence[Bytes32], depth: uint
#### `compute_shuffled_index`

```python
def compute_shuffled_index(index: ValidatorIndex, index_count: uint64, seed: Bytes32) -> ValidatorIndex:
def compute_shuffled_index(index: uint64, index_count: uint64, seed: Bytes32) -> uint64:
"""
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
Return the shuffled index corresponding to ``seed`` (and ``index_count``).
"""
assert index < index_count

# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
# See the 'generalized domain' algorithm on page 3
for current_round in range(SHUFFLE_ROUND_COUNT):
pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count
flip = ValidatorIndex((pivot + index_count - index) % index_count)
flip = (pivot + index_count - index) % index_count
position = max(index, flip)
source = hash(seed + int_to_bytes(current_round, length=1) + int_to_bytes(position // 256, length=4))
byte = source[(position % 256) // 8]
bit = (byte >> (position % 8)) % 2
index = flip if bit else index

return ValidatorIndex(index)
return index
```

#### `compute_proposer_index`
Expand All @@ -753,11 +754,11 @@ def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex]
MAX_RANDOM_BYTE = 2**8 - 1
i = 0
while True:
candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)]
candidate_index = indices[compute_shuffled_index(i % len(indices), len(indices), seed)]
random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
effective_balance = state.validators[candidate_index].effective_balance
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
return ValidatorIndex(candidate_index)
return candidate_index
i += 1
```

Expand All @@ -773,7 +774,7 @@ def compute_committee(indices: Sequence[ValidatorIndex],
"""
start = (len(indices) * index) // count
end = (len(indices) * (index + 1)) // count
return [indices[compute_shuffled_index(ValidatorIndex(i), len(indices), seed)] for i in range(start, end)]
return [indices[compute_shuffled_index(i, len(indices), seed)] for i in range(start, end)]
```

#### `compute_epoch_at_slot`
Expand Down Expand Up @@ -852,13 +853,12 @@ def compute_domain(domain_type: DomainType, fork_version: Version=None, genesis_
```python
def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
"""
Return the signing root of an object by calculating the root of the object-domain tree.
Return the signing root for the corresponding signing data.
"""
domain_wrapped_object = SigningRoot(
return hash_tree_root(SigningData(
object_root=hash_tree_root(ssz_object),
domain=domain,
)
return hash_tree_root(domain_wrapped_object)
))
```

### Beacon state accessors
Expand Down Expand Up @@ -1125,7 +1125,7 @@ def slash_validator(state: BeaconState,
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
increase_balance(state, proposer_index, proposer_reward)
increase_balance(state, whistleblower_index, whistleblower_reward - proposer_reward)
increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
```

## Genesis
Expand Down Expand Up @@ -1231,7 +1231,7 @@ def process_slots(state: BeaconState, slot: Slot) -> None:
# Process epoch on the start slot of the next epoch
if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
process_epoch(state)
state.slot += Slot(1)
state.slot = Slot(state.slot + 1)
```

```python
Expand Down Expand Up @@ -1781,7 +1781,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
# Exits must specify an epoch when they become valid; they are not valid before then
assert get_current_epoch(state) >= voluntary_exit.epoch
# Verify the validator has been active long enough
assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
# Verify signature
domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
signing_root = compute_signing_root(voluntary_exit, domain)
Expand Down
6 changes: 5 additions & 1 deletion specs/phase0/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def get_latest_attesting_balance(store: Store, root: Root) -> Gwei:
active_indices = get_active_validator_indices(state, get_current_epoch(state))
return Gwei(sum(
state.validators[i].effective_balance for i in active_indices
if (i in store.latest_messages
if (i in store.latest_messages
and get_ancestor(store, store.latest_messages[i].root, store.blocks[root].slot) == root)
))
```
Expand Down Expand Up @@ -285,6 +285,10 @@ def validate_on_attestation(store: Store, attestation: Attestation) -> None:
# Attestations must not be for blocks in the future. If not, the attestation should not be considered
assert store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot

# FFG and LMD vote must be consistent with each other
target_slot = compute_start_slot_at_epoch(target.epoch)
assert target.root == get_ancestor(store, attestation.data.beacon_block_root, target_slot)

# Attestations can only affect the fork choice of subsequent slots.
# Delay consideration in the fork choice until their slot is in the past.
assert get_current_slot(store) >= attestation.data.slot + 1
Expand Down
Loading

0 comments on commit 4d6b99b

Please sign in to comment.