Reformed attestations

This commit is contained in:
Vitalik Buterin 2019-11-03 08:17:46 -08:00 committed by Danny Ryan
parent b36820a26c
commit 6b1bc1e02f
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
1 changed files with 91 additions and 57 deletions

View File

@ -256,6 +256,13 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
) )
``` ```
### `get_attestation_shard`
```python
def get_shard(state: BeaconState, attestation: Attestation):
return (attestation.data.index + get_start_shard(state, data.slot)) % ACTIVE_SHARDS
```
## Beacon Chain Changes ## Beacon Chain Changes
### New beacon state fields ### New beacon state fields
@ -275,32 +282,22 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
light_client_signature: BLSSignature light_client_signature: BLSSignature
``` ```
### Attestation processing ## Attestation processing
### `validate_attestation`
```python ```python
def process_attestation(state: BeaconState, attestation: Attestation) -> None: def validate_attestation(state: BeaconState, attestation: Attestation) -> bool:
data = attestation.data data = attestation.data
assert data.index < ACTIVE_SHARDS assert data.index < ACTIVE_SHARDS
shard = (data.index + get_start_shard(state, data.slot)) % ACTIVE_SHARDS shard = get_shard(state, attestation)
proposer_index = get_beacon_proposer_index(state) proposer_index = get_beacon_proposer_index(state)
# Signature check # Signature check
committee = get_beacon_committee(state, get_current_epoch(state), shard) committee = get_beacon_committee(state, get_current_epoch(state), shard)
for bits in attestation.custody_bits + [attestation.aggregation_bits]: for bits in attestation.custody_bits + [attestation.aggregation_bits]:
assert len(bits) == len(committee) assert len(bits) == len(committee)
# Check signature
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
# Get attesting indices
attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bits)
# Prepare pending attestation object
pending_attestation = PendingAttestation(
aggregation_bits=attestation.aggregation_bits,
inclusion_delay=state.slot - data.slot,
crosslink_success=False,
proposer_index=proposer_index
)
# Type 1: on-time attestations # Type 1: on-time attestations
if data.custody_bits != []: if data.custody_bits != []:
# Correct slot # Correct slot
@ -312,12 +309,21 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
assert len(attestation.custody_bits) == len(offset_slots) assert len(attestation.custody_bits) == len(offset_slots)
# Correct parent block root # Correct parent block root
assert data.beacon_block_root == get_block_root_at_slot(state, state.slot - 1) assert data.beacon_block_root == get_block_root_at_slot(state, state.slot - 1)
# Apply # Type 2: delayed attestations
online_indices = get_online_indices(state) else:
if get_total_balance(state, online_indices.intersection(attesting_indices)) * 3 >= get_total_balance(state, online_indices) * 2: assert state.slot - slot_to_epoch(data.slot) < EPOCH_LENGTH
# Check correct formatting of shard transition data assert data.shard_transition_root == Hash()
transition = block.shard_transitions[shard] assert len(attestation.custody_bits) == 0
assert data.shard_transition_root == hash_tree_root(transition) ```
### `apply_shard_transition`
```python
def apply_shard_transition(state: BeaconState, shard: Shard, transition: ShardTransition) -> None:
# Slot the attestation starts counting from
start_slot = state.shard_next_slots[shard]
# Correct data root count
offset_slots = [start_slot + x for x in SHARD_BLOCK_OFFSETS if start_slot + x < state.slot]
assert len(transition.shard_data_roots) == len(transition.shard_states) == len(transition.shard_block_lengths) == len(offset_slots) assert len(transition.shard_data_roots) == len(transition.shard_states) == len(transition.shard_block_lengths) == len(offset_slots)
assert transition.start_slot == start_slot assert transition.start_slot == start_slot
@ -336,31 +342,59 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
# Save updated state # Save updated state
state.shard_states[shard] = transition.shard_states[-1] state.shard_states[shard] = transition.shard_states[-1]
state.shard_states[shard].slot = state.slot - 1 state.shard_states[shard].slot = state.slot - 1
```
# Save success (for end-of-epoch rewarding) ### `process_attestations`
pending_attestation.crosslink_success = True
```python
def process_attestations(state: BeaconState, block: BeaconBlock, attestations: Sequence[Attestation]) -> None:
pending_attestations = []
# Basic validation
for attestation in attestations:
assert validate_attestation(state, attestation)
# Process crosslinks
online_indices = get_online_indices(state)
winners = set()
for shard in range(ACTIVE_SHARDS):
# All attestations in the block for this shard
this_shard_attestations = [attestation for attestation in attestations if get_shard(state, attestation) == shard and attestation.data.slot == state.slot]
# The committee for this shard
this_shard_committee = get_beacon_committee(state, get_current_epoch(state), shard)
# Loop over all shard transition roots
for shard_transition_root in sorted(set([attestation.data.shard_transition_root for attestation in this_shard_attestations])):
all_participants = set()
participating_attestations = []
for attestation in this_shard_attestations:
participating_attestations.append(attestation)
if attestation.data.shard_transition_root == shard_transition_root:
all_participants = all_participants.union(get_attesting_indices(state, attestation.data, attestation.aggregation_bits))
if (
get_total_balance(state, online_indices.intersection(all_participants)) * 3 >=
get_total_balance(state, online_indices.intersection(this_shard_committee)) * 2
):
assert shard_transition_root == hash_tree_root(block.shard_transition)
process_crosslink(state, shard, block.shard_transition)
# Apply proposer reward and cost # Apply proposer reward and cost
estimated_attester_reward = sum([get_base_reward(state, attester) for attester in attesting_indices]) estimated_attester_reward = sum([get_base_reward(state, attester) for attester in all_participants])
increase_balance(state, proposer, estimated_attester_reward // PROPOSER_REWARD_COEFFICIENT) increase_balance(state, proposer, estimated_attester_reward // PROPOSER_REWARD_COEFFICIENT)
for shard_state, slot, length in zip(transition.shard_states, offset_slots, transition.shard_block_lengths): for shard_state, slot, length in zip(transition.shard_states, offset_slots, block.shard_transition.shard_block_lengths):
decrease_balance(state, get_shard_proposer(state, shard, slot), shard_state.gasprice * length) decrease_balance(state, get_shard_proposer(state, shard, slot), shard_state.gasprice * length)
winners.add((shard, shard_transition_root))
# Type 2: delayed attestations for index in all_participants:
else:
assert state.slot - slot_to_epoch(data.slot) < EPOCH_LENGTH
assert data.shard_transition_root == Hash()
assert len(attestation.custody_bits) == 0
for index in attesting_indices:
online_countdown[index] = ONLINE_PERIOD online_countdown[index] = ONLINE_PERIOD
for attestation in attestations:
pending_attestation = PendingAttestation(
if data.target.epoch == get_current_epoch(state): aggregation_bits=attestation.aggregation_bits,
assert data.source == state.current_justified_checkpoint data=attestation.data,
inclusion_delay=state.slot - data.slot,
crosslink_success=(attestation.shard, attestation.shard_transition_root) in winners and attestation.data.slot == state.slot,
proposer_index=proposer_index
)
if attestation.data.target.epoch == get_current_epoch(state):
assert attestation.data.source == state.current_justified_checkpoint
state.current_epoch_attestations.append(pending_attestation) state.current_epoch_attestations.append(pending_attestation)
else: else:
assert data.source == state.previous_justified_checkpoint assert attestation.data.source == state.previous_justified_checkpoint
state.previous_epoch_attestations.append(pending_attestation) state.previous_epoch_attestations.append(pending_attestation)
``` ```