Skip to content

Commit

Permalink
Merge pull request #1589 from ethereum/v010x
Browse files Browse the repository at this point in the history
Release `v0.10.1` to `master`
  • Loading branch information
djrtwo authored Jan 23, 2020
2 parents 2e3fcc1 + d4ae008 commit b74dd67
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 134 deletions.
2 changes: 1 addition & 1 deletion scripts/build_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
SSZObject = TypeVar('SSZObject', bound=SSZType)
'''
PHASE1_IMPORTS = '''from typing import (
Any, Dict, Set, Sequence, MutableSequence, NewType, Tuple, Union, TypeVar
Any, Dict, Set, Sequence, MutableSequence, NewType, Optional, Tuple, Union, TypeVar
)
from math import (
log2,
Expand Down
14 changes: 8 additions & 6 deletions specs/phase0/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
- [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch)
- [`compute_activation_exit_epoch`](#compute_activation_exit_epoch)
- [`compute_domain`](#compute_domain)
- [`compute_signing_root`](#compute_signing_root)
- [`compute_signing_root`](#compute_signing_root)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_current_epoch`](#get_current_epoch)
- [`get_previous_epoch`](#get_previous_epoch)
Expand Down Expand Up @@ -588,8 +588,8 @@ Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specificati
- `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[BLSSignature], message: Bytes, signature: BLSSignature) -> bool`
- `def AggregateVerify(pairs: Sequence[PK: BLSSignature, message: Bytes], signature: BLSSignature) -> bool`
- `def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool`
- `def AggregateVerify(pairs: Sequence[PK: BLSPubkey, message: 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.

Expand Down Expand Up @@ -788,14 +788,16 @@ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch:
#### `compute_domain`

```python
def compute_domain(domain_type: DomainType, fork_version: Version=GENESIS_FORK_VERSION) -> Domain:
def compute_domain(domain_type: DomainType, fork_version: Optional[Version]=None) -> Domain:
"""
Return the domain for the ``domain_type`` and ``fork_version``.
"""
if fork_version is None:
fork_version = GENESIS_FORK_VERSION
return Domain(domain_type + fork_version)
```

### `compute_signing_root`
#### `compute_signing_root`

```python
def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
Expand Down Expand Up @@ -1036,7 +1038,7 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:

# Compute exit queue epoch
exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
exit_queue_epoch = max(exit_epochs, default=compute_activation_exit_epoch(get_current_epoch(state)))
exit_queue_epoch = max(exit_epochs + [compute_activation_exit_epoch(get_current_epoch(state))])
exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch])
if exit_queue_churn >= get_validator_churn_limit(state):
exit_queue_epoch += Epoch(1)
Expand Down
35 changes: 20 additions & 15 deletions specs/phase0/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
elif block.slot == slot:
return root
else:
return Bytes32() # root is older than queried slot: no results.
# root is older than queried slot, thus a skip slot. Return earliest root prior to slot
return root
```

#### `get_latest_attesting_balance`
Expand Down Expand Up @@ -239,13 +240,8 @@ def should_update_justified_checkpoint(store: Store, new_justified_checkpoint: C
if compute_slots_since_epoch_start(get_current_slot(store)) < SAFE_SLOTS_TO_UPDATE_JUSTIFIED:
return True

new_justified_block = store.blocks[new_justified_checkpoint.root]
if new_justified_block.slot <= compute_start_slot_at_epoch(store.justified_checkpoint.epoch):
return False
if not (
get_ancestor(store, new_justified_checkpoint.root, store.blocks[store.justified_checkpoint.root].slot)
== store.justified_checkpoint.root
):
justified_slot = compute_start_slot_at_epoch(store.justified_checkpoint.epoch)
if not get_ancestor(store, new_justified_checkpoint.root, justified_slot) == store.justified_checkpoint.root:
return False

return True
Expand Down Expand Up @@ -283,13 +279,13 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
assert get_current_slot(store) >= block.slot
# Add new block to the store
store.blocks[hash_tree_root(block)] = block
# Check block is a descendant of the finalized block
assert (
get_ancestor(store, hash_tree_root(block), store.blocks[store.finalized_checkpoint.root].slot) ==
store.finalized_checkpoint.root
)
# Check that block is later than the finalized epoch slot
assert block.slot > compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)

# Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert block.slot > finalized_slot
# Check block is a descendant of the finalized block at the checkpoint finalized slot
assert get_ancestor(store, hash_tree_root(block), finalized_slot) == store.finalized_checkpoint.root

# Check the block is valid and compute the post-state
state = state_transition(pre_state, signed_block, True)
# Add new state for this block to the store
Expand All @@ -305,6 +301,15 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
# Update finalized checkpoint
if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
store.finalized_checkpoint = state.finalized_checkpoint
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)

# Update justified if new justified is later than store justified
# or if store justified is not in chain with finalized checkpoint
if (
state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch
or get_ancestor(store, store.justified_checkpoint.root, finalized_slot) != store.finalized_checkpoint.root
):
store.justified_checkpoint = state.current_justified_checkpoint
```

#### `on_attestation`
Expand Down
4 changes: 2 additions & 2 deletions specs/phase0/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ It consists of four main sections:
- [How do we upgrade gossip channels (e.g. changes in encoding, compression)?](#how-do-we-upgrade-gossip-channels-eg-changes-in-encoding-compression)
- [Why must all clients use the same gossip topic instead of one negotiated between each peer pair?](#why-must-all-clients-use-the-same-gossip-topic-instead-of-one-negotiated-between-each-peer-pair)
- [Why are the topics strings and not hashes?](#why-are-the-topics-strings-and-not-hashes)
- [Why are we overriding the default libp2p pubsub `message-id`?](#why-are-we-overriding-the-default-libp2p-pubsub-message-id)
- [Why are we overriding the default libp2p pubsub `message-id`?](#why-are-we-overriding-the-default-libp2p-pubsub-message-id)
- [Why is there `MAXIMUM_GOSSIP_CLOCK_DISPARITY` when validating slot ranges of messages in gossip subnets?](#why-is-there-maximum_gossip_clock_disparity-when-validating-slot-ranges-of-messages-in-gossip-subnets)
- [Why are there `ATTESTATION_SUBNET_COUNT` attestation subnets?](#why-are-there-attestation_subnet_count-attestation-subnets)
- [Why are attestations limited to be broadcast on gossip channels within `SLOTS_PER_EPOCH` slots?](#why-are-attestations-limited-to-be-broadcast-on-gossip-channels-within-slots_per_epoch-slots)
Expand Down Expand Up @@ -759,7 +759,7 @@ No security or privacy guarantees are lost as a result of choosing plaintext top

Furthermore, the Eth2 topic names are shorter than their digest equivalents (assuming SHA-256 hash), so hashing topics would bloat messages unnecessarily.

## Why are we overriding the default libp2p pubsub `message-id`?
### Why are we overriding the default libp2p pubsub `message-id`?

For our current purposes, there is no need to address messages based on source peer, and it seems likely we might even override the message `from` to obfuscate the peer. By overriding the default `message-id` to use content-addressing we can filter unnecessary duplicates before hitting the application layer.

Expand Down
4 changes: 2 additions & 2 deletions specs/phase0/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ A validator must initialize many parameters locally before submitting a deposit

#### BLS public key

Validator public keys are [G1 points](../bls_signature.md#g1-points) on the [BLS12-381 curve](https://z.cash/blog/new-snark-curve). A private key, `privkey`, must be securely generated along with the resultant `pubkey`. This `privkey` must be "hot", that is, constantly available to sign data throughout the lifetime of the validator.
Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BLS12-381 curve](https://z.cash/blog/new-snark-curve). A private key, `privkey`, must be securely generated along with the resultant `pubkey`. This `privkey` must be "hot", that is, constantly available to sign data throughout the lifetime of the validator.

#### BLS withdrawal key

Expand Down Expand Up @@ -128,7 +128,7 @@ To submit a deposit:

### Process deposit

Deposits cannot be processed into the beacon chain until the Eth1 block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes _a minimum_ of `ETH1_FOLLOW_DISTANCE` Eth1 blocks (~4 hours) plus `ETH1_DATA_VOTING_PERIOD` epochs (~1.7 hours). Once the requisite Eth1 data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validators` within an epoch or two. The validator is then in a queue to be activated.
Deposits cannot be processed into the beacon chain until the Eth1 block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes _a minimum_ of `ETH1_FOLLOW_DISTANCE` Eth1 blocks (~4 hours) plus `SLOTS_PER_ETH1_VOTING_PERIOD` slots (~3.4 hours). Once the requisite Eth1 data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validators` within an epoch or two. The validator is then in a queue to be activated.

### Validator index

Expand Down
90 changes: 90 additions & 0 deletions tests/core/pyspec/eth2spec/test/fork_choice/test_on_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,48 @@ def test_on_block_before_finalized(spec, state):
run_on_block(spec, store, signed_block, False)


@with_all_phases
@spec_state_test
def test_on_block_finalized_skip_slots(spec, state):
# Initialization
store = spec.get_genesis_store(state)
time = 100
spec.on_tick(store, time)

store.finalized_checkpoint = spec.Checkpoint(
epoch=store.finalized_checkpoint.epoch + 2,
root=store.finalized_checkpoint.root
)

# Build block that includes the skipped slots up to finality in chain
block = build_empty_block(spec, state, spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + 2)
signed_block = state_transition_and_sign_block(spec, state, block)
spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT)
run_on_block(spec, store, signed_block)


@with_all_phases
@spec_state_test
def test_on_block_finalized_skip_slots_not_in_skip_chain(spec, state):
# Initialization
store = spec.get_genesis_store(state)

store.finalized_checkpoint = spec.Checkpoint(
epoch=store.finalized_checkpoint.epoch + 2,
root=store.finalized_checkpoint.root
)

# First transition through the epoch to ensure no skipped slots
state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store)

# Now build a block at later slot than finalized epoch
# Includes finalized block in chain, but not at appropriate skip slot
block = build_empty_block(spec, state, spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + 2)
signed_block = state_transition_and_sign_block(spec, state, block)
spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT)
run_on_block(spec, store, signed_block, False)


@with_all_phases
@spec_state_test
def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
Expand Down Expand Up @@ -214,3 +256,51 @@ def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
assert store.justified_checkpoint == previously_justified
# ensure the best from the series was stored
assert store.best_justified_checkpoint == best_justified_checkpoint


@with_all_phases
@spec_state_test
def test_on_block_outside_safe_slots_but_finality(spec, state):
# Initialization
store = spec.get_genesis_store(state)
time = 100
spec.on_tick(store, time)

next_epoch(spec, state)
spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT)
state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store)
next_epoch(spec, state)
spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT)
last_block_root = hash_tree_root(last_signed_block.message)

# Mock justified block in store
just_block = build_empty_block_for_next_slot(spec, state)
# Slot is same as justified checkpoint so does not trigger an override in the store
just_block.slot = spec.compute_start_slot_at_epoch(store.justified_checkpoint.epoch)
store.blocks[just_block.hash_tree_root()] = just_block

# Step time past safe slots
spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.SECONDS_PER_SLOT)
assert spec.get_current_slot(store) % spec.SLOTS_PER_EPOCH >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED

# Mock justified and finalized update in state
just_fin_state = store.block_states[last_block_root]
new_justified = spec.Checkpoint(
epoch=store.justified_checkpoint.epoch + 1,
root=just_block.hash_tree_root(),
)
new_finalized = spec.Checkpoint(
epoch=store.finalized_checkpoint.epoch + 1,
root=just_block.parent_root,
)
just_fin_state.current_justified_checkpoint = new_justified
just_fin_state.finalized_checkpoint = new_finalized

# Build and add block that includes the new justified/finalized info
block = build_empty_block_for_next_slot(spec, just_fin_state)
signed_block = state_transition_and_sign_block(spec, deepcopy(just_fin_state), block)

run_on_block(spec, store, signed_block)

assert store.finalized_checkpoint == new_finalized
assert store.justified_checkpoint == new_justified
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ def test_success(spec, state):

yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)

assert state.validators[validator_index].exit_epoch == spec.compute_activation_exit_epoch(current_epoch)


@with_all_phases
@spec_state_test
Expand Down Expand Up @@ -110,6 +112,28 @@ def test_success_exit_queue(spec, state):
)


@with_all_phases
@spec_state_test
def test_default_exit_epoch_subsequent_exit(spec, state):
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]

signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)

# Exit one validator prior to this new one
exited_index = spec.get_active_validator_indices(state, current_epoch)[-1]
state.validators[exited_index].exit_epoch = current_epoch - 1

yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)

assert state.validators[validator_index].exit_epoch == spec.compute_activation_exit_epoch(current_epoch)


@with_all_phases
@spec_state_test
def test_validator_exit_in_future(spec, state):
Expand Down
2 changes: 1 addition & 1 deletion tests/generators/bls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The base unit is bytes48 of which only 381 bits are used

## Resources

- [Eth2 spec](../../specs/bls_signature.md)
- [Eth2 spec](../../../specs/phase0/beacon-chain.md#bls-signatures)
- [Finite Field Arithmetic](http://www.springeronline.com/sgw/cda/pageitems/document/cda_downloaddocument/0,11996,0-0-45-110359-0,00.pdf)
- Chapter 2 of [Elliptic Curve Cryptography](http://cacr.uwaterloo.ca/ecc/). Darrel Hankerson, Alfred Menezes, and Scott Vanstone
- [Zcash BLS parameters](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381)
Expand Down
Loading

0 comments on commit b74dd67

Please sign in to comment.