Skip to content
This repository has been archived by the owner on Jul 1, 2021. It is now read-only.

Merklization friendly pending attestations and update per-epoch processing: crosslink, rewards and penalties #390

Merged
merged 23 commits into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c84bb01
Split `latest_attestations`
NIC619 Mar 8, 2019
63a3b02
Update `get_winning_root`
NIC619 Mar 8, 2019
a3ac0ca
Update `process_crosslinks`
NIC619 Mar 9, 2019
96879ae
Expand rewards/penalites map to entire registry and fix latest_crossl…
NIC619 Mar 9, 2019
f9bde80
Move penalties for `attesting_active_validators` section up for bette…
NIC619 Mar 9, 2019
7bf7c31
Update `_process_rewards_and_penalties_for_finality`
NIC619 Mar 9, 2019
b96f3b4
Handle `get_base_reward` when no previous balance
NIC619 Mar 9, 2019
3afb6a4
Fix linting error and move `_is_eligible_for_punishment` into `_proce…
NIC619 Mar 9, 2019
c358dcc
Implement `get_inactivity_penalty`
NIC619 Mar 11, 2019
adc512f
Change `get_winning_root` to `get_winning_root_and_participants`
NIC619 Mar 11, 2019
e79333e
Merge attestion inclusion reward into finality reward
NIC619 Mar 11, 2019
ae91d6e
Make `get_previous_epoch_boundary_attestations` helper funciton
NIC619 Mar 11, 2019
17c8345
Separate `_process_rewards_and_penalties_for_finality` into `compute_…
NIC619 Mar 11, 2019
e7e9e8e
Return both rewards and penalties map instead of just rewards map
NIC619 Mar 11, 2019
6e253c6
Update rewards and penalties tests
NIC619 Mar 11, 2019
93f3935
Remove `SignedGwei` type and `RewardSettlementContext`
NIC619 Mar 11, 2019
7162347
Apply PR feedback: fix namings and comments
NIC619 Mar 13, 2019
4bf74ef
Apply PR feedback:
NIC619 Mar 13, 2019
a8ad3a0
Apply PR feedback: naming and type checking
NIC619 Mar 17, 2019
9dc8c6c
Combine two `_filter_attestations_by` helpers
NIC619 Mar 17, 2019
ea0d44f
Add check for 0 total balance in `get_base_reward`
NIC619 Mar 17, 2019
9691de3
Apply PR feedback:
NIC619 Mar 17, 2019
73a4377
Remove no-op if/else branches
NIC619 Mar 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions eth2/beacon/committee_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,11 +456,12 @@ def get_attestation_participants(state: 'BeaconState',
return get_members_from_bitfield(committee, bitfield)


@to_tuple
@to_set
def get_attester_indices_from_attesttion(
def get_attester_indices_from_attestations(
*,
state: 'BeaconState',
attestations: Iterable['Attestation'],
attestations: Sequence['Attestation'],
committee_config: CommitteeConfig) -> Iterable[ValidatorIndex]:
for a in attestations:
yield from get_attestation_participants(
Expand Down
19 changes: 0 additions & 19 deletions eth2/beacon/datastructures/reward_settlement_context.py

This file was deleted.

176 changes: 105 additions & 71 deletions eth2/beacon/epoch_processing_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,20 @@
to_set,
)

from eth.constants import ZERO_HASH32
from eth2._utils.numeric import integer_squareroot
from eth2.beacon.committee_helpers import (
get_attestation_participants,
get_attester_indices_from_attesttion,
get_attester_indices_from_attestations,
)
from eth2.beacon.configs import (
CommitteeConfig,
)
from eth2.beacon.exceptions import (
NoWinningRootError,
)
from eth2.beacon.helpers import (
get_block_root,
get_epoch_start_slot,
get_effective_balance,
get_total_balance,
slot_to_epoch,
)
from eth2.beacon.typing import (
Epoch,
Expand All @@ -41,6 +39,7 @@
)

from eth2.beacon.datastructures.inclusion_info import InclusionInfo
from eth2.beacon.types.crosslink_records import CrosslinkRecord
from eth2.beacon.types.pending_attestation_records import (
PendingAttestationRecord,
)
Expand All @@ -54,38 +53,31 @@


@to_tuple
def get_current_epoch_attestations(
state: 'BeaconState',
slots_per_epoch: int) -> Iterable[PendingAttestationRecord]:
current_epoch = state.current_epoch(slots_per_epoch)
for attestation in state.latest_attestations:
if current_epoch == slot_to_epoch(attestation.data.slot, slots_per_epoch):
yield attestation


@to_tuple
def get_previous_epoch_attestations(
def get_previous_epoch_boundary_attestations(
state: 'BeaconState',
slots_per_epoch: int,
genesis_epoch: Epoch) -> Iterable[PendingAttestationRecord]:
previous_epoch = state.previous_epoch(slots_per_epoch, genesis_epoch)
for attestation in state.latest_attestations:
if previous_epoch == slot_to_epoch(attestation.data.slot, slots_per_epoch):
genesis_epoch: Epoch,
latest_block_roots_length: int) -> Iterable[PendingAttestationRecord]:
beacon_block_root = get_block_root(
state,
get_epoch_start_slot(
state.previous_epoch(slots_per_epoch, genesis_epoch),
slots_per_epoch,
),
latest_block_roots_length,
)
for attestation in state.previous_epoch_attestations:
if attestation.data.beacon_block_root == beacon_block_root:
yield attestation


@to_tuple
def get_previous_epoch_head_attestations(
def get_previous_epoch_matching_head_attestations(
state: 'BeaconState',
slots_per_epoch: int,
NIC619 marked this conversation as resolved.
Show resolved Hide resolved
genesis_epoch: Epoch,
latest_block_roots_length: int) -> Iterable[PendingAttestationRecord]:
previous_epoch_attestations = get_previous_epoch_attestations(
state,
slots_per_epoch,
genesis_epoch,
)
for attestation in previous_epoch_attestations:
for attestation in state.previous_epoch_attestations:
beacon_block_root = get_block_root(
state,
attestation.data.slot,
Expand All @@ -95,46 +87,61 @@ def get_previous_epoch_head_attestations(
yield attestation


def get_winning_root(
@to_tuple
def _filter_attestations_by_latest_crosslinks_and_shard(
attestations: Sequence[PendingAttestationRecord],
latest_crosslink: CrosslinkRecord,
shard: Shard) -> Iterable[PendingAttestationRecord]:
for attestation in attestations:
is_latest_crosslink_matched = attestation.data.latest_crosslink == latest_crosslink
is_shard_matched = attestation.data.shard == shard
if is_latest_crosslink_matched and is_shard_matched:
yield attestation


def get_winning_root_and_participants(
*,
state: 'BeaconState',
shard: Shard,
attestations: Sequence[PendingAttestationRecord],
max_deposit_amount: Gwei,
committee_config: CommitteeConfig) -> Tuple[Hash32, Gwei]:
winning_root = None
winning_root_balance: Gwei = Gwei(0)
crosslink_data_roots = set(
[
a.data.crosslink_data_root for a in attestations
if a.data.shard == shard
]
effective_balances: Dict[ValidatorIndex, Gwei],
committee_config: CommitteeConfig) -> Tuple[Hash32, Tuple[ValidatorIndex, ...]]:
valid_attestations = _filter_attestations_by_latest_crosslinks_and_shard(
state.current_epoch_attestations + state.previous_epoch_attestations,
state.latest_crosslinks[shard],
shard,
)
all_roots = set([a.data.crosslink_data_root for a in valid_attestations])

# handle when no attestations for shard available
if len(all_roots) == 0:
return (Hash32(ZERO_HASH32), tuple())

def get_attestations_for(root: Hash32) -> Sequence[PendingAttestationRecord]:
return [a for a in valid_attestations if a.data.crosslink_data_root == root]

# Winning crosslink root is the root with the most votes for it, ties broken in favor of
# lexicographically higher hash
winning_root: Hash32 = max(
all_roots,
key=lambda r: (
get_attesting_balance_from_attestations(
state=state,
NIC619 marked this conversation as resolved.
Show resolved Hide resolved
effective_balances=effective_balances,
attestations=get_attestations_for(r),
committee_config=committee_config,
),
r,
),
)
for crosslink_data_root in crosslink_data_roots:
attesting_validator_indices = get_attester_indices_from_attesttion(

return (
winning_root,
get_attester_indices_from_attestations(
state=state,
attestations=[
a
for a in attestations
if a.data.shard == shard and a.data.crosslink_data_root == crosslink_data_root
],
attestations=get_attestations_for(winning_root),
committee_config=committee_config,
)
total_attesting_balance = get_total_balance(
state.validator_balances,
attesting_validator_indices,
max_deposit_amount,
)
if total_attesting_balance > winning_root_balance:
winning_root = crosslink_data_root
winning_root_balance = total_attesting_balance
elif total_attesting_balance == winning_root_balance and winning_root_balance > 0:
if crosslink_data_root < winning_root:
winning_root = crosslink_data_root

if winning_root is None:
raise NoWinningRootError
return (winning_root, winning_root_balance)
),
)


@to_tuple
Expand All @@ -161,13 +168,6 @@ def get_epoch_boundary_attesting_balances(
state: 'BeaconState',
config: 'BeaconConfig') -> Tuple[Gwei, Gwei]:

current_epoch_attestations = get_current_epoch_attestations(state, config.SLOTS_PER_EPOCH)
previous_epoch_attestations = get_previous_epoch_attestations(
state,
config.SLOTS_PER_EPOCH,
config.GENESIS_EPOCH,
)

previous_epoch_boundary_root = get_block_root(
state,
get_epoch_start_slot(previous_epoch, config.SLOTS_PER_EPOCH),
Expand All @@ -176,7 +176,7 @@ def get_epoch_boundary_attesting_balances(

previous_epoch_boundary_attester_indices = get_epoch_boundary_attester_indices(
state,
current_epoch_attestations + previous_epoch_attestations,
state.current_epoch_attestations + state.previous_epoch_attestations,
state.previous_justified_epoch,
previous_epoch_boundary_root,
CommitteeConfig(config),
Expand All @@ -196,7 +196,7 @@ def get_epoch_boundary_attesting_balances(

current_epoch_boundary_attester_indices = get_epoch_boundary_attester_indices(
state,
current_epoch_attestations,
state.current_epoch_attestations,
state.justified_epoch,
current_epoch_boundary_root,
CommitteeConfig(config),
Expand All @@ -221,18 +221,52 @@ def get_total_balance_from_effective_balances(
)


def get_attesting_balance_from_attestations(
*,
state: 'BeaconState',
effective_balances: Dict[ValidatorIndex, Gwei],
attestations: Sequence[PendingAttestationRecord],
committee_config: CommitteeConfig) -> Gwei:
return get_total_balance_from_effective_balances(
effective_balances,
get_attester_indices_from_attestations(
state=state,
attestations=attestations,
committee_config=committee_config,
),
)


def get_base_reward(
*,
state: 'BeaconState',
index: ValidatorIndex,
base_reward_quotient: int,
previous_total_balance: Gwei,
max_deposit_amount: Gwei) -> Gwei:
if previous_total_balance == 0:
return Gwei(0)
adjusted_quotient = (
integer_squareroot(previous_total_balance) // base_reward_quotient
)
NIC619 marked this conversation as resolved.
Show resolved Hide resolved
return Gwei(
get_effective_balance(
state.validator_balances,
index,
max_deposit_amount,
) // base_reward_quotient // 5
) // adjusted_quotient // 5
)


def get_inactivity_penalty(
*,
base_reward: Gwei,
effective_balance: Gwei,
epochs_since_finality: int,
inactivity_penalty_quotient: int) -> Gwei:
return Gwei(
base_reward +
effective_balance * epochs_since_finality // inactivity_penalty_quotient // 2
)


Expand Down
7 changes: 0 additions & 7 deletions eth2/beacon/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ class ProposerIndexError(PyEVMError):
pass


class NoWinningRootError(PyEVMError):
"""
Raised when no shard block root is attested to among the attestations provided.
"""
pass


class NoCommitteeAssignment(PyEVMError):
"""
Raised when no potential crosslink committee assignment.
Expand Down
3 changes: 2 additions & 1 deletion eth2/beacon/on_genesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ def get_genesis_beacon_state(*,
current_shuffling_seed=ZERO_HASH32,

# Finality
previous_epoch_attestations=(),
current_epoch_attestations=(),
previous_justified_epoch=genesis_epoch,
justified_epoch=genesis_epoch,
justification_bitfield=0,
Expand All @@ -113,7 +115,6 @@ def get_genesis_beacon_state(*,
latest_block_roots=(ZERO_HASH32,) * latest_block_roots_length,
latest_active_index_roots=(ZERO_HASH32,) * latest_active_index_roots_length,
latest_slashed_balances=(Gwei(0),) * latest_slashed_exit_length,
latest_attestations=(),
batched_block_roots=(),

# Ethereum 1.0 chain data
Expand Down
Loading