From a89ecced1cd4fdac79f9dc6e12e91c4e579ec0ac Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 27 May 2021 09:02:51 -0600 Subject: [PATCH] Modify sync committee logic and parameters to reduce variance Sync committee rewards as currently implemented significantly increase variance in proposer rewards: https://github.com/ethereum/eth2.0-specs/issues/2448 For example, if there are 200000 validators (6.4m ETH staked), then during each 1/4-eek (~54 hour) period there is a chance of 512/200000 that a validator will get accepted into the sync committee, so on average that will happen once every 200000/512 * 1/4 = 97.6 eeks, or close to two years. The payout of this "lottery" is 1/8 of that, or ~12.2 eeks (a bit less than four months) of revenue. This is much more severe than block proposing (a chance of 1/200000 per slot, or a lottery worth ~0.38 eeks of revenue once every ~3.05 eeks). This PR makes three changes to cut make the sync committee lottery less drastic and bring variance closer in line with what is available from block proposing: * Reduce the `SYNC_REWARD_WEIGHT` from 8 to 2 * Add a penalty for not participating in the sync committee, so that despite the first change the total net reward for participating vs not participating is only cut down by 2x * Reduce the sync committee period from 1/4 eek to 1/8 eek (~27 hours) With these three factors combined, the lottery reduces to ~1.5 eeks of revenue, on average occurring every ~48 eeks. Validators who are maximally unlucky (ie. never become part of a sync committee) only lose ~3.12% of their rewards instead of ~12.5%. The compromises that this approach makes are: * In the extreme case where >50% of proposers are operating efficiently, being in a sync committee becomes a net burden. However, this should be extremely rare, and in such cases validators would likely be suffering inactivity leak penalties anyway. * Incentive to participate in a sync committee decreased by 2x (but this is IMO an improvement; sync committees are _not_ as important as proposals and deserve to have lower rewards) * Minimum data syncing needed to maintain a light client increases by 2x (from 24 kB per 54 hours to 24 kB per 27 hours). A burden for on-chain light clients, but still insignificant for others. --- specs/altair/beacon-chain.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 7412a8490..d6a942771 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -86,10 +86,10 @@ Altair is the first beacon chain hard fork. Its main features are: | Name | Value | | - | - | -| `TIMELY_SOURCE_WEIGHT` | `uint64(12)` | -| `TIMELY_TARGET_WEIGHT` | `uint64(24)` | -| `TIMELY_HEAD_WEIGHT` | `uint64(12)` | -| `SYNC_REWARD_WEIGHT` | `uint64(8)` | +| `TIMELY_SOURCE_WEIGHT` | `uint64(14)` | +| `TIMELY_TARGET_WEIGHT` | `uint64(26)` | +| `TIMELY_HEAD_WEIGHT` | `uint64(14)` | +| `SYNC_REWARD_WEIGHT` | `uint64(2)` | | `PROPOSER_WEIGHT` | `uint64(8)` | | `WEIGHT_DENOMINATOR` | `uint64(64)` | @@ -129,7 +129,7 @@ This patch updates a few configuration values to move penalty parameters closer | Name | Value | Unit | Duration | | - | - | - | - | | `SYNC_COMMITTEE_SIZE` | `uint64(2**9)` (= 512) | Validators | | -| `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` | `uint64(2**9)` (= 512) | epochs | ~54 hours | +| `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` | `uint64(2**8)` (= 256) | epochs | ~27 hours | ## Configuration @@ -579,10 +579,12 @@ def process_sync_committee(state: BeaconState, aggregate: SyncAggregate) -> None # Apply participant and proposer rewards all_pubkeys = [v.pubkey for v in state.validators] committee_indices = [ValidatorIndex(all_pubkeys.index(pubkey)) for pubkey in state.current_sync_committee.pubkeys] - participant_indices = [index for index, bit in zip(committee_indices, aggregate.sync_committee_bits) if bit] - for participant_index in participant_indices: - increase_balance(state, participant_index, participant_reward) - increase_balance(state, get_beacon_proposer_index(state), proposer_reward) + for index, participation_bit in zip(committee_indices, aggregate.sync_committee_bits): + if participant_bit: + increase_balance(state, participant_index, participant_reward) + increase_balance(state, get_beacon_proposer_index(state), proposer_reward) + else: + decrease_balance(state, participant_index, participant_reward) ``` ### Epoch processing