Merge pull request #2246 from ethereum/sync_rewards
refactor sync committee rewards
This commit is contained in:
commit
e2c9a15aaf
|
@ -10,7 +10,7 @@
|
||||||
- [Custom types](#custom-types)
|
- [Custom types](#custom-types)
|
||||||
- [Constants](#constants)
|
- [Constants](#constants)
|
||||||
- [Participation flag indices](#participation-flag-indices)
|
- [Participation flag indices](#participation-flag-indices)
|
||||||
- [Participation flag fractions](#participation-flag-fractions)
|
- [Incentivization weights](#incentivization-weights)
|
||||||
- [Misc](#misc)
|
- [Misc](#misc)
|
||||||
- [Configuration](#configuration)
|
- [Configuration](#configuration)
|
||||||
- [Updated penalty values](#updated-penalty-values)
|
- [Updated penalty values](#updated-penalty-values)
|
||||||
|
@ -28,12 +28,13 @@
|
||||||
- [`Predicates`](#predicates)
|
- [`Predicates`](#predicates)
|
||||||
- [`eth2_fast_aggregate_verify`](#eth2_fast_aggregate_verify)
|
- [`eth2_fast_aggregate_verify`](#eth2_fast_aggregate_verify)
|
||||||
- [Misc](#misc-2)
|
- [Misc](#misc-2)
|
||||||
- [`get_flag_indices_and_numerators`](#get_flag_indices_and_numerators)
|
- [`get_flag_indices_and_weights`](#get_flag_indices_and_weights)
|
||||||
- [`add_flag`](#add_flag)
|
- [`add_flag`](#add_flag)
|
||||||
- [`has_flag`](#has_flag)
|
- [`has_flag`](#has_flag)
|
||||||
- [Beacon state accessors](#beacon-state-accessors)
|
- [Beacon state accessors](#beacon-state-accessors)
|
||||||
- [`get_sync_committee_indices`](#get_sync_committee_indices)
|
- [`get_sync_committee_indices`](#get_sync_committee_indices)
|
||||||
- [`get_sync_committee`](#get_sync_committee)
|
- [`get_sync_committee`](#get_sync_committee)
|
||||||
|
- [`get_base_reward_per_increment`](#get_base_reward_per_increment)
|
||||||
- [`get_base_reward`](#get_base_reward)
|
- [`get_base_reward`](#get_base_reward)
|
||||||
- [`get_unslashed_participating_indices`](#get_unslashed_participating_indices)
|
- [`get_unslashed_participating_indices`](#get_unslashed_participating_indices)
|
||||||
- [`get_flag_index_deltas`](#get_flag_index_deltas)
|
- [`get_flag_index_deltas`](#get_flag_index_deltas)
|
||||||
|
@ -61,7 +62,7 @@ Altair is the first beacon chain hard fork. Its main features are:
|
||||||
|
|
||||||
* sync committees to support light clients
|
* sync committees to support light clients
|
||||||
* incentive accounting reforms to reduce spec complexity
|
* incentive accounting reforms to reduce spec complexity
|
||||||
* penalty parameter updates to move them to their planned maximally punitive configuration
|
* penalty parameter updates towards their planned maximally punitive values
|
||||||
|
|
||||||
## Custom types
|
## Custom types
|
||||||
|
|
||||||
|
@ -79,16 +80,17 @@ Altair is the first beacon chain hard fork. Its main features are:
|
||||||
| `TIMELY_SOURCE_FLAG_INDEX` | `1` |
|
| `TIMELY_SOURCE_FLAG_INDEX` | `1` |
|
||||||
| `TIMELY_TARGET_FLAG_INDEX` | `2` |
|
| `TIMELY_TARGET_FLAG_INDEX` | `2` |
|
||||||
|
|
||||||
### Participation flag fractions
|
### Incentivization weights
|
||||||
|
|
||||||
| Name | Value |
|
| Name | Value |
|
||||||
| - | - |
|
| - | - |
|
||||||
| `TIMELY_HEAD_FLAG_NUMERATOR` | `12` |
|
| `TIMELY_HEAD_WEIGHT` | `12` |
|
||||||
| `TIMELY_SOURCE_FLAG_NUMERATOR` | `12` |
|
| `TIMELY_SOURCE_WEIGHT` | `12` |
|
||||||
| `TIMELY_TARGET_FLAG_NUMERATOR` | `32` |
|
| `TIMELY_TARGET_WEIGHT` | `24` |
|
||||||
| `FLAG_DENOMINATOR` | `64` |
|
| `SYNC_REWARD_WEIGHT` | `8` |
|
||||||
|
| `WEIGHT_DENOMINATOR` | `64` |
|
||||||
|
|
||||||
*Note*: The sum of the participatition flag fractions (7/8) plus the proposer reward fraction (1/8) equals 1.
|
*Note*: The sum of the weight fractions (7/8) plus the proposer inclusion fraction (1/8) equals 1.
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
|
@ -229,14 +231,14 @@ def eth2_fast_aggregate_verify(pubkeys: Sequence[BLSPubkey], message: Bytes32, s
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
#### `get_flag_indices_and_numerators`
|
#### `get_flag_indices_and_weights`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_flag_indices_and_numerators() -> Sequence[Tuple[int, int]]:
|
def get_flag_indices_and_weights() -> Sequence[Tuple[int, int]]:
|
||||||
return (
|
return (
|
||||||
(TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_FLAG_NUMERATOR),
|
(TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_WEIGHT),
|
||||||
(TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_FLAG_NUMERATOR),
|
(TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_WEIGHT),
|
||||||
(TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_FLAG_NUMERATOR),
|
(TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_WEIGHT),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -297,15 +299,21 @@ def get_sync_committee(state: BeaconState, epoch: Epoch) -> SyncCommittee:
|
||||||
return SyncCommittee(pubkeys=pubkeys, pubkey_aggregates=pubkey_aggregates)
|
return SyncCommittee(pubkeys=pubkeys, pubkey_aggregates=pubkey_aggregates)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `get_base_reward_per_increment`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_base_reward_per_increment(state: BeaconState) -> Gwei:
|
||||||
|
return Gwei(EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR // integer_squareroot(get_total_active_balance(state)))
|
||||||
|
```
|
||||||
|
|
||||||
#### `get_base_reward`
|
#### `get_base_reward`
|
||||||
|
|
||||||
*Note*: The function `get_base_reward` is modified with the removal of `BASE_REWARDS_PER_EPOCH`.
|
*Note*: The function `get_base_reward` is modified with the removal of `BASE_REWARDS_PER_EPOCH`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||||
total_balance = get_total_active_balance(state)
|
increments = state.validators[index].effective_balance // EFFECTIVE_BALANCE_INCREMENT
|
||||||
effective_balance = state.validators[index].effective_balance
|
return Gwei(increments * get_base_reward_per_increment(state))
|
||||||
return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_unslashed_participating_indices`
|
#### `get_unslashed_participating_indices`
|
||||||
|
@ -328,9 +336,7 @@ def get_unslashed_participating_indices(state: BeaconState, flag_index: int, epo
|
||||||
#### `get_flag_index_deltas`
|
#### `get_flag_index_deltas`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_flag_index_deltas(state: BeaconState,
|
def get_flag_index_deltas(state: BeaconState, flag_index: int, weight: uint64) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
|
||||||
flag_index: int,
|
|
||||||
numerator: uint64) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
|
|
||||||
"""
|
"""
|
||||||
Return the deltas for a given flag index by scanning through the participation flags.
|
Return the deltas for a given flag index by scanning through the participation flags.
|
||||||
"""
|
"""
|
||||||
|
@ -345,12 +351,12 @@ def get_flag_index_deltas(state: BeaconState,
|
||||||
if index in unslashed_participating_indices:
|
if index in unslashed_participating_indices:
|
||||||
if is_in_inactivity_leak(state):
|
if is_in_inactivity_leak(state):
|
||||||
# This flag reward cancels the inactivity penalty corresponding to the flag index
|
# This flag reward cancels the inactivity penalty corresponding to the flag index
|
||||||
rewards[index] += Gwei(base_reward * numerator // FLAG_DENOMINATOR)
|
rewards[index] += Gwei(base_reward * weight // WEIGHT_DENOMINATOR)
|
||||||
else:
|
else:
|
||||||
reward_numerator = base_reward * numerator * unslashed_participating_increments
|
reward_numerator = base_reward * weight * unslashed_participating_increments
|
||||||
rewards[index] += Gwei(reward_numerator // (active_increments * FLAG_DENOMINATOR))
|
rewards[index] += Gwei(reward_numerator // (active_increments * WEIGHT_DENOMINATOR))
|
||||||
else:
|
else:
|
||||||
penalties[index] += Gwei(base_reward * numerator // FLAG_DENOMINATOR)
|
penalties[index] += Gwei(base_reward * weight // WEIGHT_DENOMINATOR)
|
||||||
return rewards, penalties
|
return rewards, penalties
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -370,9 +376,9 @@ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], S
|
||||||
previous_epoch = get_previous_epoch(state)
|
previous_epoch = get_previous_epoch(state)
|
||||||
matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, previous_epoch)
|
matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, previous_epoch)
|
||||||
for index in get_eligible_validator_indices(state):
|
for index in get_eligible_validator_indices(state):
|
||||||
for (_, numerator) in get_flag_indices_and_numerators():
|
for (_, weight) in get_flag_indices_and_weights():
|
||||||
# This inactivity penalty cancels the flag reward corresponding to the flag index
|
# This inactivity penalty cancels the flag reward corresponding to the flag index
|
||||||
penalties[index] += Gwei(get_base_reward(state, index) * numerator // FLAG_DENOMINATOR)
|
penalties[index] += Gwei(get_base_reward(state, index) * weight // WEIGHT_DENOMINATOR)
|
||||||
if index not in matching_target_indices:
|
if index not in matching_target_indices:
|
||||||
penalty_numerator = state.validators[index].effective_balance * state.inactivity_scores[index]
|
penalty_numerator = state.validators[index].effective_balance * state.inactivity_scores[index]
|
||||||
penalty_denominator = INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR
|
penalty_denominator = INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR
|
||||||
|
@ -465,13 +471,13 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||||
# Update epoch participation flags
|
# Update epoch participation flags
|
||||||
proposer_reward_numerator = 0
|
proposer_reward_numerator = 0
|
||||||
for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
||||||
for flag_index, flag_numerator in get_flag_indices_and_numerators():
|
for flag_index, weight in get_flag_indices_and_weights():
|
||||||
if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
|
if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
|
||||||
epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||||
proposer_reward_numerator += get_base_reward(state, index) * flag_numerator
|
proposer_reward_numerator += get_base_reward(state, index) * weight
|
||||||
|
|
||||||
# Reward proposer
|
# Reward proposer
|
||||||
proposer_reward = Gwei(proposer_reward_numerator // (FLAG_DENOMINATOR * PROPOSER_REWARD_QUOTIENT))
|
proposer_reward = Gwei(proposer_reward_numerator // (WEIGHT_DENOMINATOR * PROPOSER_REWARD_QUOTIENT))
|
||||||
increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -525,26 +531,28 @@ def process_sync_committee(state: BeaconState, aggregate: SyncAggregate) -> None
|
||||||
# Verify sync committee aggregate signature signing over the previous slot block root
|
# Verify sync committee aggregate signature signing over the previous slot block root
|
||||||
previous_slot = Slot(max(int(state.slot), 1) - 1)
|
previous_slot = Slot(max(int(state.slot), 1) - 1)
|
||||||
committee_indices = get_sync_committee_indices(state, get_current_epoch(state))
|
committee_indices = get_sync_committee_indices(state, get_current_epoch(state))
|
||||||
participant_indices = [index for index, bit in zip(committee_indices, aggregate.sync_committee_bits) if bit]
|
included_indices = [index for index, bit in zip(committee_indices, aggregate.sync_committee_bits) if bit]
|
||||||
committee_pubkeys = state.current_sync_committee.pubkeys
|
committee_pubkeys = state.current_sync_committee.pubkeys
|
||||||
participant_pubkeys = [pubkey for pubkey, bit in zip(committee_pubkeys, aggregate.sync_committee_bits) if bit]
|
included_pubkeys = [pubkey for pubkey, bit in zip(committee_pubkeys, aggregate.sync_committee_bits) if bit]
|
||||||
domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot))
|
domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot))
|
||||||
signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain)
|
signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain)
|
||||||
assert eth2_fast_aggregate_verify(participant_pubkeys, signing_root, aggregate.sync_committee_signature)
|
assert eth2_fast_aggregate_verify(included_pubkeys, signing_root, aggregate.sync_committee_signature)
|
||||||
|
|
||||||
# Reward sync committee participants
|
# Compute the maximum sync rewards for the slot
|
||||||
proposer_rewards = Gwei(0)
|
total_active_increments = get_total_active_balance(state) // EFFECTIVE_BALANCE_INCREMENT
|
||||||
active_validator_count = uint64(len(get_active_validator_indices(state, get_current_epoch(state))))
|
total_base_rewards = Gwei(get_base_reward_per_increment(state) * total_active_increments)
|
||||||
for participant_index in participant_indices:
|
max_epoch_rewards = Gwei(total_base_rewards * SYNC_REWARD_WEIGHT // WEIGHT_DENOMINATOR)
|
||||||
proposer_reward = get_proposer_reward(state, participant_index)
|
max_slot_rewards = Gwei(max_epoch_rewards * len(included_indices) // len(committee_indices) // SLOTS_PER_EPOCH)
|
||||||
proposer_rewards += proposer_reward
|
|
||||||
base_reward = get_base_reward(state, participant_index)
|
|
||||||
max_participant_reward = base_reward - proposer_reward
|
|
||||||
reward = Gwei(max_participant_reward * active_validator_count // (len(committee_indices) * SLOTS_PER_EPOCH))
|
|
||||||
increase_balance(state, participant_index, reward)
|
|
||||||
|
|
||||||
# Reward beacon proposer
|
# Compute the participant and proposer sync rewards
|
||||||
increase_balance(state, get_beacon_proposer_index(state), proposer_rewards)
|
committee_effective_balance = sum([state.validators[index].effective_balance for index in included_indices])
|
||||||
|
committee_effective_balance = max(EFFECTIVE_BALANCE_INCREMENT, committee_effective_balance)
|
||||||
|
for included_index in included_indices:
|
||||||
|
effective_balance = state.validators[included_index].effective_balance
|
||||||
|
inclusion_reward = Gwei(max_slot_rewards * effective_balance // committee_effective_balance)
|
||||||
|
proposer_reward = Gwei(inclusion_reward // PROPOSER_REWARD_QUOTIENT)
|
||||||
|
increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
||||||
|
increase_balance(state, included_index, inclusion_reward - proposer_reward)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Epoch processing
|
### Epoch processing
|
||||||
|
@ -635,7 +643,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
|
||||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||||
return
|
return
|
||||||
|
|
||||||
flag_indices_and_numerators = get_flag_indices_and_numerators()
|
flag_indices_and_numerators = get_flag_indices_and_weights()
|
||||||
flag_deltas = [get_flag_index_deltas(state, index, numerator) for (index, numerator) in flag_indices_and_numerators]
|
flag_deltas = [get_flag_index_deltas(state, index, numerator) for (index, numerator) in flag_indices_and_numerators]
|
||||||
deltas = flag_deltas + [get_inactivity_penalty_deltas(state)]
|
deltas = flag_deltas + [get_inactivity_penalty_deltas(state)]
|
||||||
for (rewards, penalties) in deltas:
|
for (rewards, penalties) in deltas:
|
||||||
|
|
|
@ -65,7 +65,8 @@ def get_committee_indices(spec, state, duplicates=False):
|
||||||
@always_bls
|
@always_bls
|
||||||
def test_invalid_signature_missing_participant(spec, state):
|
def test_invalid_signature_missing_participant(spec, state):
|
||||||
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state))
|
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state))
|
||||||
random_participant = random.choice(committee)
|
rng = random.Random(2020)
|
||||||
|
random_participant = rng.choice(committee)
|
||||||
|
|
||||||
yield 'pre', state
|
yield 'pre', state
|
||||||
|
|
||||||
|
@ -88,7 +89,8 @@ def test_invalid_signature_missing_participant(spec, state):
|
||||||
@always_bls
|
@always_bls
|
||||||
def test_invalid_signature_extra_participant(spec, state):
|
def test_invalid_signature_extra_participant(spec, state):
|
||||||
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state))
|
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state))
|
||||||
random_participant = random.choice(committee)
|
rng = random.Random(3030)
|
||||||
|
random_participant = rng.choice(committee)
|
||||||
|
|
||||||
block = build_empty_block_for_next_slot(spec, state)
|
block = build_empty_block_for_next_slot(spec, state)
|
||||||
# Exclude one signature even though the block claims the entire committee participated.
|
# Exclude one signature even though the block claims the entire committee participated.
|
||||||
|
@ -105,11 +107,92 @@ def test_invalid_signature_extra_participant(spec, state):
|
||||||
yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
|
yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
|
||||||
|
|
||||||
|
|
||||||
def compute_sync_committee_participant_reward(spec, state, participant_index, active_validator_count, committee_size):
|
def compute_sync_committee_inclusion_reward(spec, state, participant_index, committee, committee_bits):
|
||||||
base_reward = spec.get_base_reward(state, participant_index)
|
total_active_increments = spec.get_total_active_balance(state) // spec.EFFECTIVE_BALANCE_INCREMENT
|
||||||
proposer_reward = spec.get_proposer_reward(state, participant_index)
|
total_base_rewards = spec.Gwei(spec.get_base_reward_per_increment(state) * total_active_increments)
|
||||||
max_participant_reward = base_reward - proposer_reward
|
max_epoch_rewards = spec.Gwei(total_base_rewards * spec.SYNC_REWARD_WEIGHT // spec.WEIGHT_DENOMINATOR)
|
||||||
return max_participant_reward * active_validator_count // committee_size // spec.SLOTS_PER_EPOCH
|
included_indices = [index for index, bit in zip(committee, committee_bits) if bit]
|
||||||
|
max_slot_rewards = spec.Gwei(max_epoch_rewards * len(included_indices) // len(committee) // spec.SLOTS_PER_EPOCH)
|
||||||
|
|
||||||
|
# Compute the participant and proposer sync rewards
|
||||||
|
committee_effective_balance = sum([state.validators[index].effective_balance for index in included_indices])
|
||||||
|
committee_effective_balance = max(spec.EFFECTIVE_BALANCE_INCREMENT, committee_effective_balance)
|
||||||
|
effective_balance = state.validators[participant_index].effective_balance
|
||||||
|
return spec.Gwei(max_slot_rewards * effective_balance // committee_effective_balance)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_sync_committee_participant_reward(spec, state, participant_index, committee, committee_bits):
|
||||||
|
included_indices = [index for index, bit in zip(committee, committee_bits) if bit]
|
||||||
|
multiplicities = Counter(included_indices)
|
||||||
|
|
||||||
|
inclusion_reward = compute_sync_committee_inclusion_reward(
|
||||||
|
spec, state, participant_index, committee, committee_bits,
|
||||||
|
)
|
||||||
|
proposer_reward = spec.Gwei(inclusion_reward // spec.PROPOSER_REWARD_QUOTIENT)
|
||||||
|
return spec.Gwei((inclusion_reward - proposer_reward) * multiplicities[participant_index])
|
||||||
|
|
||||||
|
|
||||||
|
def compute_sync_committee_proposer_reward(spec, state, committee, committee_bits):
|
||||||
|
proposer_reward = 0
|
||||||
|
for index, bit in zip(committee, committee_bits):
|
||||||
|
if not bit:
|
||||||
|
continue
|
||||||
|
inclusion_reward = compute_sync_committee_inclusion_reward(
|
||||||
|
spec, state, index, committee, committee_bits,
|
||||||
|
)
|
||||||
|
proposer_reward += spec.Gwei(inclusion_reward // spec.PROPOSER_REWARD_QUOTIENT)
|
||||||
|
return proposer_reward
|
||||||
|
|
||||||
|
|
||||||
|
def validate_sync_committee_rewards(spec, pre_state, post_state, committee, committee_bits, proposer_index):
|
||||||
|
for index in range(len(post_state.validators)):
|
||||||
|
reward = 0
|
||||||
|
if index in committee:
|
||||||
|
reward += compute_sync_committee_participant_reward(
|
||||||
|
spec,
|
||||||
|
pre_state,
|
||||||
|
index,
|
||||||
|
committee,
|
||||||
|
committee_bits,
|
||||||
|
)
|
||||||
|
|
||||||
|
if proposer_index == index:
|
||||||
|
reward += compute_sync_committee_proposer_reward(
|
||||||
|
spec,
|
||||||
|
pre_state,
|
||||||
|
committee,
|
||||||
|
committee_bits,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert post_state.balances[index] == pre_state.balances[index] + reward
|
||||||
|
|
||||||
|
|
||||||
|
def run_successful_sync_committee_test(spec, state, committee, committee_bits):
|
||||||
|
yield 'pre', state
|
||||||
|
|
||||||
|
pre_state = state.copy()
|
||||||
|
|
||||||
|
block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
block.body.sync_aggregate = spec.SyncAggregate(
|
||||||
|
sync_committee_bits=committee_bits,
|
||||||
|
sync_committee_signature=compute_aggregate_sync_committee_signature(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
block.slot - 1,
|
||||||
|
[index for index, bit in zip(committee, committee_bits) if bit],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
yield from run_sync_committee_processing(spec, state, block)
|
||||||
|
|
||||||
|
validate_sync_committee_rewards(
|
||||||
|
spec,
|
||||||
|
pre_state,
|
||||||
|
state,
|
||||||
|
committee,
|
||||||
|
committee_bits,
|
||||||
|
block.proposer_index,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases_except([PHASE0, PHASE1])
|
@with_all_phases_except([PHASE0, PHASE1])
|
||||||
|
@ -118,45 +201,25 @@ def compute_sync_committee_participant_reward(spec, state, participant_index, ac
|
||||||
def test_sync_committee_rewards_nonduplicate_committee(spec, state):
|
def test_sync_committee_rewards_nonduplicate_committee(spec, state):
|
||||||
committee = get_committee_indices(spec, state, duplicates=False)
|
committee = get_committee_indices(spec, state, duplicates=False)
|
||||||
committee_size = len(committee)
|
committee_size = len(committee)
|
||||||
|
committee_bits = [True] * committee_size
|
||||||
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
|
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
|
||||||
|
|
||||||
# Preconditions of this test case
|
# Preconditions of this test case
|
||||||
assert active_validator_count >= spec.SYNC_COMMITTEE_SIZE
|
assert active_validator_count >= spec.SYNC_COMMITTEE_SIZE
|
||||||
assert committee_size == len(set(committee))
|
assert committee_size == len(set(committee))
|
||||||
|
|
||||||
yield 'pre', state
|
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits)
|
||||||
|
|
||||||
pre_balances = state.balances.copy()
|
|
||||||
|
|
||||||
block = build_empty_block_for_next_slot(spec, state)
|
@with_all_phases_except([PHASE0, PHASE1])
|
||||||
block.body.sync_aggregate = spec.SyncAggregate(
|
@spec_state_test
|
||||||
sync_committee_bits=[True] * committee_size,
|
@always_bls
|
||||||
sync_committee_signature=compute_aggregate_sync_committee_signature(
|
def test_sync_committee_rewards_not_full_participants(spec, state):
|
||||||
spec,
|
committee = get_committee_indices(spec, state, duplicates=False)
|
||||||
state,
|
rng = random.Random(1010)
|
||||||
block.slot - 1,
|
committee_bits = [rng.choice([True, False]) for _ in committee]
|
||||||
committee,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
yield from run_sync_committee_processing(spec, state, block)
|
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits)
|
||||||
|
|
||||||
for index in range(len(state.validators)):
|
|
||||||
expected_reward = 0
|
|
||||||
|
|
||||||
if index == block.proposer_index:
|
|
||||||
expected_reward += sum([spec.get_proposer_reward(state, index) for index in committee])
|
|
||||||
|
|
||||||
if index in committee:
|
|
||||||
expected_reward += compute_sync_committee_participant_reward(
|
|
||||||
spec,
|
|
||||||
state,
|
|
||||||
index,
|
|
||||||
active_validator_count,
|
|
||||||
committee_size
|
|
||||||
)
|
|
||||||
|
|
||||||
assert state.balances[index] == pre_balances[index] + expected_reward
|
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases_except([PHASE0, PHASE1])
|
@with_all_phases_except([PHASE0, PHASE1])
|
||||||
|
@ -165,44 +228,14 @@ def test_sync_committee_rewards_nonduplicate_committee(spec, state):
|
||||||
def test_sync_committee_rewards_duplicate_committee(spec, state):
|
def test_sync_committee_rewards_duplicate_committee(spec, state):
|
||||||
committee = get_committee_indices(spec, state, duplicates=True)
|
committee = get_committee_indices(spec, state, duplicates=True)
|
||||||
committee_size = len(committee)
|
committee_size = len(committee)
|
||||||
|
committee_bits = [True] * committee_size
|
||||||
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
|
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
|
||||||
|
|
||||||
# Preconditions of this test case
|
# Preconditions of this test case
|
||||||
assert active_validator_count < spec.SYNC_COMMITTEE_SIZE
|
assert active_validator_count < spec.SYNC_COMMITTEE_SIZE
|
||||||
assert committee_size > len(set(committee))
|
assert committee_size > len(set(committee))
|
||||||
|
|
||||||
pre_balances = state.balances.copy()
|
yield from run_successful_sync_committee_test(spec, state, committee, committee_bits)
|
||||||
block = build_empty_block_for_next_slot(spec, state)
|
|
||||||
block.body.sync_aggregate = spec.SyncAggregate(
|
|
||||||
sync_committee_bits=[True] * committee_size,
|
|
||||||
sync_committee_signature=compute_aggregate_sync_committee_signature(
|
|
||||||
spec,
|
|
||||||
state,
|
|
||||||
block.slot - 1,
|
|
||||||
committee,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
yield from run_sync_committee_processing(spec, state, block)
|
|
||||||
|
|
||||||
multiplicities = Counter(committee)
|
|
||||||
|
|
||||||
for index in range(len(state.validators)):
|
|
||||||
expected_reward = 0
|
|
||||||
|
|
||||||
if index == block.proposer_index:
|
|
||||||
expected_reward += sum([spec.get_proposer_reward(state, index) for index in committee])
|
|
||||||
|
|
||||||
if index in committee:
|
|
||||||
reward = compute_sync_committee_participant_reward(
|
|
||||||
spec,
|
|
||||||
state,
|
|
||||||
index,
|
|
||||||
active_validator_count,
|
|
||||||
committee_size,
|
|
||||||
)
|
|
||||||
expected_reward += reward * multiplicities[index]
|
|
||||||
|
|
||||||
assert state.balances[index] == pre_balances[index] + expected_reward
|
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases_except([PHASE0, PHASE1])
|
@with_all_phases_except([PHASE0, PHASE1])
|
||||||
|
|
|
@ -62,13 +62,13 @@ def run_deltas(spec, state):
|
||||||
|
|
||||||
if is_post_altair(spec):
|
if is_post_altair(spec):
|
||||||
def get_source_deltas(state):
|
def get_source_deltas(state):
|
||||||
return spec.get_flag_index_deltas(state, spec.TIMELY_SOURCE_FLAG_INDEX, spec.TIMELY_SOURCE_FLAG_NUMERATOR)
|
return spec.get_flag_index_deltas(state, spec.TIMELY_SOURCE_FLAG_INDEX, spec.TIMELY_SOURCE_WEIGHT)
|
||||||
|
|
||||||
def get_head_deltas(state):
|
def get_head_deltas(state):
|
||||||
return spec.get_flag_index_deltas(state, spec.TIMELY_HEAD_FLAG_INDEX, spec.TIMELY_HEAD_FLAG_NUMERATOR)
|
return spec.get_flag_index_deltas(state, spec.TIMELY_HEAD_FLAG_INDEX, spec.TIMELY_HEAD_WEIGHT)
|
||||||
|
|
||||||
def get_target_deltas(state):
|
def get_target_deltas(state):
|
||||||
return spec.get_flag_index_deltas(state, spec.TIMELY_TARGET_FLAG_INDEX, spec.TIMELY_TARGET_FLAG_NUMERATOR)
|
return spec.get_flag_index_deltas(state, spec.TIMELY_TARGET_FLAG_INDEX, spec.TIMELY_TARGET_WEIGHT)
|
||||||
|
|
||||||
yield from run_attestation_component_deltas(
|
yield from run_attestation_component_deltas(
|
||||||
spec,
|
spec,
|
||||||
|
@ -227,8 +227,8 @@ def run_get_inactivity_penalty_deltas(spec, state):
|
||||||
base_penalty = cancel_base_rewards_per_epoch * base_reward - spec.get_proposer_reward(state, index)
|
base_penalty = cancel_base_rewards_per_epoch * base_reward - spec.get_proposer_reward(state, index)
|
||||||
else:
|
else:
|
||||||
base_penalty = sum(
|
base_penalty = sum(
|
||||||
base_reward * numerator // spec.FLAG_DENOMINATOR
|
base_reward * numerator // spec.WEIGHT_DENOMINATOR
|
||||||
for (_, numerator) in spec.get_flag_indices_and_numerators()
|
for (_, numerator) in spec.get_flag_indices_and_weights()
|
||||||
)
|
)
|
||||||
|
|
||||||
if not has_enough_for_reward(spec, state, index):
|
if not has_enough_for_reward(spec, state, index):
|
||||||
|
|
Loading…
Reference in New Issue