Skip to content

Commit

Permalink
Merge branch 'dev' into fix-bls-domain-type
Browse files Browse the repository at this point in the history
  • Loading branch information
djrtwo committed Jul 1, 2019
2 parents 5b2b3cf + 2ab55bf commit af57190
Show file tree
Hide file tree
Showing 17 changed files with 159 additions and 133 deletions.
2 changes: 1 addition & 1 deletion scripts/build_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def apply_constants_preset(preset: Dict[str, Any]) -> None:
global_vars[k] = v
# Deal with derived constants
global_vars['GENESIS_EPOCH'] = slot_to_epoch(GENESIS_SLOT)
global_vars['GENESIS_EPOCH'] = compute_epoch_of_slot(GENESIS_SLOT)
# Initialize SSZ types again, to account for changed lengths
init_SSZ_types()
Expand Down
165 changes: 92 additions & 73 deletions specs/core/0_beacon-chain.md

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions specs/core/0_fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- [Time parameters](#time-parameters)
- [Fork choice](#fork-choice)
- [Helpers](#helpers)
- [`Checkpoint`](#checkpoint)
- [`LatestMessage`](#latestmessage)
- [`Store`](#store)
- [`get_genesis_store`](#get_genesis_store)
- [`get_ancestor`](#get_ancestor)
Expand Down Expand Up @@ -113,8 +113,8 @@ def get_latest_attesting_balance(store: Store, root: Hash) -> 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 and
get_ancestor(store, store.latest_messages[i].root, store.blocks[root].slot) == root)
if (i in store.latest_messages
and get_ancestor(store, store.latest_messages[i].root, store.blocks[root].slot) == root)
))
```

Expand All @@ -124,7 +124,7 @@ def get_latest_attesting_balance(store: Store, root: Hash) -> Gwei:
def get_head(store: Store) -> Hash:
# Execute the LMD-GHOST fork choice
head = store.justified_checkpoint.root
justified_slot = epoch_start_slot(store.justified_checkpoint.epoch)
justified_slot = compute_start_slot_of_epoch(store.justified_checkpoint.epoch)
while True:
children = [
root for root in store.blocks.keys()
Expand Down Expand Up @@ -162,7 +162,7 @@ def on_block(store: Store, block: BeaconBlock) -> None:
store.finalized_checkpoint.root
)
# Check that block is later than the finalized epoch slot
assert block.slot > epoch_start_slot(store.finalized_checkpoint.epoch)
assert block.slot > compute_start_slot_of_epoch(store.finalized_checkpoint.epoch)
# Check the block is valid and compute the post-state
state = state_transition(pre_state, block)
# Add new state for this block to the store
Expand Down Expand Up @@ -190,11 +190,11 @@ def on_attestation(store: Store, attestation: Attestation) -> None:

# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
base_state = store.block_states[target.root].copy()
assert store.time >= base_state.genesis_time + epoch_start_slot(target.epoch) * SECONDS_PER_SLOT
assert store.time >= base_state.genesis_time + compute_start_slot_of_epoch(target.epoch) * SECONDS_PER_SLOT

# Store target checkpoint state if not yet seen
if target not in store.checkpoint_states:
process_slots(base_state, epoch_start_slot(target.epoch))
process_slots(base_state, compute_start_slot_of_epoch(target.epoch))
store.checkpoint_states[target] = base_state
target_state = store.checkpoint_states[target]

Expand All @@ -205,7 +205,7 @@ def on_attestation(store: Store, attestation: Attestation) -> None:

# Get state at the `target` to validate attestation and calculate the committees
indexed_attestation = get_indexed_attestation(target_state, attestation)
validate_indexed_attestation(target_state, indexed_attestation)
assert is_valid_indexed_attestation(target_state, indexed_attestation)

# Update latest messages
for i in indexed_attestation.custody_bit_0_indices + indexed_attestation.custody_bit_1_indices:
Expand Down
11 changes: 7 additions & 4 deletions specs/core/1_custody-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [Max operations per block](#max-operations-per-block)
- [Reward and penalty quotients](#reward-and-penalty-quotients)
- [Signature domains](#signature-domains)
- [TODO PLACEHOLDER](#todo-placeholder)
- [Data structures](#data-structures)
- [Custody objects](#custody-objects)
- [`CustodyChunkChallenge`](#custodychunkchallenge)
Expand All @@ -33,6 +34,7 @@
- [Helpers](#helpers)
- [`ceillog2`](#ceillog2)
- [`get_crosslink_chunk_count`](#get_crosslink_chunk_count)
- [`get_bit`](#get_bit)
- [`get_custody_chunk_bit`](#get_custody_chunk_bit)
- [`get_chunk_bits_root`](#get_chunk_bits_root)
- [`get_randao_epoch_for_custody_period`](#get_randao_epoch_for_custody_period)
Expand Down Expand Up @@ -474,9 +476,10 @@ For each `challenge` in `block.body.custody_chunk_challenges`, run the following
```python
def process_chunk_challenge(state: BeaconState, challenge: CustodyChunkChallenge) -> None:
# Verify the attestation
validate_indexed_attestation(state, get_indexed_attestation(state, challenge.attestation))
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, challenge.attestation))
# Verify it is not too late to challenge
assert slot_to_epoch(challenge.attestation.data.slot) >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
assert (compute_epoch_of_slot(challenge.attestation.data.slot)
>= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY)
responder = state.validators[challenge.responder_index]
assert responder.exit_epoch >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
# Verify the responder participated in the attestation
Expand Down Expand Up @@ -517,7 +520,7 @@ For each `challenge` in `block.body.custody_bit_challenges`, run the following f
```python
def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> None:
attestation = challenge.attestation
epoch = slot_to_epoch(attestation.data.slot)
epoch = compute_epoch_of_slot(attestation.data.slot)
shard = attestation.data.crosslink.shard

# Verify challenge signature
Expand All @@ -527,7 +530,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) ->
# Verify challenger is slashable
assert is_slashable_validator(challenger, get_current_epoch(state))
# Verify attestation
validate_indexed_attestation(state, get_indexed_attestation(state, attestation))
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
# Verify attestation is eligible for challenging
responder = state.validators[challenge.responder_index]
assert epoch + responder.max_reveal_lateness <= get_reveal_period(state, challenge.responder_index)
Expand Down
20 changes: 11 additions & 9 deletions specs/core/1_shard-data-chains.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
- [Signature domains](#signature-domains)
- [TODO PLACEHOLDER](#todo-placeholder)
- [Data structures](#data-structures)
- [`ShardBlockBody`](#shardblockbody)
- [`ShardAttestation`](#shardattestation)
Expand Down Expand Up @@ -165,7 +166,7 @@ def get_persistent_committee(state: BeaconState,
"""
Return the persistent committee for the given ``shard`` at the given ``slot``.
"""
epoch = slot_to_epoch(slot)
epoch = compute_epoch_of_slot(slot)
earlier_start_epoch = Epoch(epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2)
later_start_epoch = Epoch(epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD)

Expand All @@ -183,8 +184,8 @@ def get_persistent_committee(state: BeaconState,
# Take not-yet-cycled-out validators from earlier committee and already-cycled-in validators from
# later committee; return a sorted list of the union of the two, deduplicated
return sorted(list(set(
[i for i in earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(state, epoch, i)] +
[i for i in later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(state, epoch, i)]
[i for i in earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(state, epoch, i)]
+ [i for i in later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(state, epoch, i)]
)))
```

Expand Down Expand Up @@ -242,7 +243,7 @@ def verify_shard_attestation_signature(state: BeaconState,
pubkey=bls_aggregate_pubkeys(pubkeys),
message_hash=data.shard_block_root,
signature=attestation.aggregate_signature,
domain=get_domain(state, DOMAIN_SHARD_ATTESTER, slot_to_epoch(data.slot))
domain=get_domain(state, DOMAIN_SHARD_ATTESTER, compute_epoch_of_slot(data.slot))
)
```

Expand Down Expand Up @@ -341,7 +342,7 @@ def is_valid_shard_block(beacon_blocks: Sequence[BeaconBlock],
pubkey=beacon_state.validators[proposer_index].pubkey,
message_hash=signing_root(candidate),
signature=candidate.signature,
domain=get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, slot_to_epoch(candidate.slot)),
domain=get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, compute_epoch_of_slot(candidate.slot)),
)

return True
Expand Down Expand Up @@ -400,16 +401,17 @@ def is_valid_beacon_attestation(shard: Shard,
assert candidate.data.previous_crosslink.data_root == Hash()
else:
previous_attestation = next(
(attestation for attestation in valid_attestations if
attestation.data.crosslink.data_root == candidate.data.previous_crosslink.data_root),
(attestation for attestation in valid_attestations
if attestation.data.crosslink.data_root == candidate.data.previous_crosslink.data_root),
None,
)
assert previous_attestation is not None
assert candidate.data.previous_attestation.epoch < slot_to_epoch(candidate.data.slot)
assert candidate.data.previous_attestation.epoch < compute_epoch_of_slot(candidate.data.slot)

# Check crosslink data root
start_epoch = beacon_state.crosslinks[shard].epoch
end_epoch = min(slot_to_epoch(candidate.data.slot) - CROSSLINK_LOOKBACK, start_epoch + MAX_EPOCHS_PER_CROSSLINK)
end_epoch = min(compute_epoch_of_slot(candidate.data.slot) - CROSSLINK_LOOKBACK,
start_epoch + MAX_EPOCHS_PER_CROSSLINK)
blocks = []
for slot in range(start_epoch * SLOTS_PER_EPOCH, end_epoch * SLOTS_PER_EPOCH):
blocks.append(shard_blocks[slot])
Expand Down
8 changes: 4 additions & 4 deletions specs/light_client/sync_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def compute_committee(header: BeaconBlockHeader,
maximal_later_committee = validator_memory.later_period_data.committee
earlier_start_epoch = get_earlier_start_epoch(header.slot)
later_start_epoch = get_later_start_epoch(header.slot)
epoch = slot_to_epoch(header.slot)
epoch = compute_epoch_of_slot(header.slot)

committee_count = max(
earlier_validator_count // (SHARD_COUNT * TARGET_COMMITTEE_SIZE),
Expand Down Expand Up @@ -153,8 +153,8 @@ def compute_committee(header: BeaconBlockHeader,
# Take not-yet-cycled-out validators from earlier committee and already-cycled-in validators from
# later committee; return a sorted list of the union of the two, deduplicated
return sorted(list(set(
[i for i in actual_earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(i)] +
[i for i in actual_later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(i)]
[i for i in actual_earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(i)]
+ [i for i in actual_later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(i)]
)))
```

Expand Down Expand Up @@ -192,7 +192,7 @@ def verify_block_validity_proof(proof: BlockValidityProof, validator_memory: Val
pubkey=group_public_key,
message_hash=hash_tree_root(shard_parent_block),
signature=proof.shard_aggregate_signature,
domain=get_domain(state, slot_to_epoch(shard_block.slot), DOMAIN_SHARD_ATTESTER),
domain=get_domain(state, compute_epoch_of_slot(shard_block.slot), DOMAIN_SHARD_ATTESTER),
)
```

Expand Down
4 changes: 2 additions & 2 deletions specs/test_formats/bls/msg_hash_g2_uncompressed.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Test format: BLS hash-uncompressed

A BLS uncompressed-hash to G2.
A BLS uncompressed-hash to G2.

## Test case format

```yaml
input:
input:
message: bytes32
domain: bytes8 -- the BLS domain
output: List[List[bytes48]] -- 3 lists, each a length of two
Expand Down
2 changes: 1 addition & 1 deletion specs/test_formats/bls/sign_msg.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Test format: BLS sign message

Message signing with BLS should produce a signature.
Message signing with BLS should produce a signature.

## Test case format

Expand Down
25 changes: 12 additions & 13 deletions specs/validator/0_beacon-chain-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ To submit a deposit:
- Pack the validator's [initialization parameters](#initialization) into `deposit_data`, a [`DepositData`](../core/0_beacon-chain.md#depositdata) SSZ object.
- Let `amount` be the amount in Gwei to be deposited by the validator where `MIN_DEPOSIT_AMOUNT <= amount <= MAX_EFFECTIVE_BALANCE`.
- Set `deposit_data.amount = amount`.
- Let `signature` be the result of `bls_sign` of the `signing_root(deposit_data)` with `domain=bls_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `bls_domain` will default to zeroes there).
- Let `signature` be the result of `bls_sign` of the `signing_root(deposit_data)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there).
- Send a transaction on the Ethereum 1.0 chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96])` along with a deposit of `amount` Gwei.

*Note*: Deposits made for the same `pubkey` are treated as for the same validator. A singular `Validator` will be added to `state.validators` with each additional deposit amount added to the validator's balance. A validator can only be activated when total deposits for the validator pubkey meet or exceed `MAX_EFFECTIVE_BALANCE`.
Expand Down Expand Up @@ -132,10 +132,9 @@ Once a validator is activated, the validator is assigned [responsibilities](#bea
A validator can get committee assignments for a given epoch using the following helper via `get_committee_assignment(state, epoch, validator_index)` where `epoch <= next_epoch`.

```python
def get_committee_assignment(
state: BeaconState,
epoch: Epoch,
validator_index: ValidatorIndex) -> Tuple[List[ValidatorIndex], Shard, Slot]:
def get_committee_assignment(state: BeaconState,
epoch: Epoch,
validator_index: ValidatorIndex) -> Tuple[List[ValidatorIndex], Shard, Slot]:
"""
Return the committee assignment in the ``epoch`` for ``validator_index``.
``assignment`` returned is a tuple of the following form:
Expand All @@ -147,7 +146,7 @@ def get_committee_assignment(
assert epoch <= next_epoch

committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH
start_slot = epoch_start_slot(epoch)
start_slot = compute_start_slot_of_epoch(epoch)
for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
slot_start_shard = (get_start_shard(state, epoch) + offset) % SHARD_COUNT
Expand Down Expand Up @@ -211,10 +210,10 @@ Set `block.randao_reveal = epoch_signature` where `epoch_signature` is defined a
```python
epoch_signature = bls_sign(
privkey=validator.privkey, # privkey stored locally, not in state
message_hash=hash_tree_root(slot_to_epoch(block.slot)),
message_hash=hash_tree_root(compute_epoch_of_slot(block.slot)),
domain=get_domain(
fork=fork, # `fork` is the fork object at the slot `block.slot`
epoch=slot_to_epoch(block.slot),
epoch=compute_epoch_of_slot(block.slot),
domain_type=DOMAIN_RANDAO,
)
)
Expand Down Expand Up @@ -253,7 +252,7 @@ block_signature = bls_sign(
message_hash=signing_root(block),
domain=get_domain(
fork=fork, # `fork` is the fork object at the slot `block.slot`
epoch=slot_to_epoch(block.slot),
epoch=compute_epoch_of_slot(block.slot),
domain_type=DOMAIN_BEACON_BLOCK,
)
)
Expand Down Expand Up @@ -309,7 +308,7 @@ Set `attestation_data.beacon_block_root = signing_root(head_block)`.

*Note*: `epoch_boundary_block_root` can be looked up in the state using:

- Let `start_slot = epoch_start_slot(get_current_epoch(head_state))`.
- Let `start_slot = compute_start_slot_of_epoch(get_current_epoch(head_state))`.
- Let `epoch_boundary_block_root = signing_root(head_block) if start_slot == head_state.slot else get_block_root(state, start_slot)`.

##### Crosslink vote
Expand Down Expand Up @@ -359,7 +358,7 @@ signed_attestation_data = bls_sign(
message_hash=attestation_message,
domain=get_domain(
fork=fork, # `fork` is the fork object at the slot, `attestation_data.slot`
epoch=slot_to_epoch(attestation_data.slot),
epoch=compute_epoch_of_slot(attestation_data.slot),
domain_type=DOMAIN_ATTESTATION,
)
)
Expand All @@ -379,7 +378,7 @@ To avoid "proposer slashings", a validator must not sign two conflicting [`Beaco

Specifically, when signing a `BeaconBlock`, a validator should perform the following steps in the following order:

1. Save a record to hard disk that a beacon block has been signed for the `epoch=slot_to_epoch(block.slot)`.
1. Save a record to hard disk that a beacon block has been signed for the `epoch=compute_epoch_of_slot(block.slot)`.
2. Generate and broadcast the block.

If the software crashes at some point within this routine, then when the validator comes back online, the hard disk has the record of the *potentially* signed/broadcast block and can effectively avoid slashing.
Expand All @@ -390,7 +389,7 @@ To avoid "attester slashings", a validator must not sign two conflicting [`Attes

Specifically, when signing an `Attestation`, a validator should perform the following steps in the following order:

1. Save a record to hard disk that an attestation has been signed for source (i.e. `attestation_data.source_epoch`) and target (i.e. `slot_to_epoch(attestation_data.slot)`).
1. Save a record to hard disk that an attestation has been signed for source (i.e. `attestation_data.source_epoch`) and target (i.e. `compute_epoch_of_slot(attestation_data.slot)`).
2. Generate and broadcast attestation.

If the software crashes at some point within this routine, then when the validator comes back online, the hard disk has the record of the *potentially* signed/broadcast attestation and can effectively avoid slashing.
2 changes: 1 addition & 1 deletion test_generators/shuffling/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
def shuffling_case(seed, count):
yield 'seed', '0x' + seed.hex()
yield 'count', count
yield 'shuffled', [int(spec.shuffled_index(i, count, seed)) for i in range(count)]
yield 'shuffled', [int(spec.compute_shuffled_index(i, count, seed)) for i in range(count)]


@to_tuple
Expand Down
Loading

0 comments on commit af57190

Please sign in to comment.