Part 3: Annotated Specification
Types, Constants, Presets, and Configuration
Preset
The "presets" are consistent collections of configuration variables that are bundled together. The specs repo currently defines two sets of presets, mainnet and minimal. The mainnet configuration is running in production on the beacon chain; minimal is often used for testing. Other configurations are possible. For example, Teku uses a swift configuration for acceptance testing.
All the values discussed below are from the mainnet configuration.
You'll notice that most of these values are powers of two. There's no huge significance to this. Computer scientists think it's neat, and it ensures that things cleanly divide other things in general. There is a view that this practice helps to minimise bike-shedding (endless arguments over trivial matters).
Some of the configuration parameters below are quite technical and perhaps obscure. I'll take the opportunity here to introduce some concepts, and give more detailed explanations when they appear in later chapters.
Misc
Name | Value |
---|---|
MAX_COMMITTEES_PER_SLOT |
uint64(2**6) (= 64) |
TARGET_COMMITTEE_SIZE |
uint64(2**7) (= 128) |
MAX_VALIDATORS_PER_COMMITTEE |
uint64(2**11) (= 2,048) |
SHUFFLE_ROUND_COUNT |
uint64(90) |
MAX_COMMITTEES_PER_SLOT
Validators are organised into committees to do their work. At any one time, each validator is a member of exactly one beacon chain committee, and is called on to make an attestation exactly once per epoch. An attestation is a vote for, or a statement of, the validator's view of the chain at that point in time.
On the beacon chain, up to 64 committees are active in a slot and effectively act as a single committee as far as the fork-choice rule is concerned. They all vote on the proposed block for the slot, and their votes/attestations are pooled. In a similar way, all committees active during an epoch (that is, the whole active validator set) act effectively as a single committee as far as justification and finalisation are concerned.
The number 64 is intended to map to one committee per shard once data shards are deployed, since these committees will also vote on shard crosslinks.
Note that sync committees are a different thing: there is only one sync committee active at any time.
TARGET_COMMITTEE_SIZE
To achieve a desirable level of security, committees need to be larger than a certain size. This makes it infeasible for an attacker to randomly end up with a super-majority in a committee even if they control a significant number of validators. The target here is a kind of lower-bound on committee size. If there are not enough validators for all committees to have at least 128 members, then, as a first measure, the number of committees per slot is reduced to maintain this minimum. Only if there are fewer than SLOTS_PER_EPOCH
* TARGET_COMMITTEE_SIZE
= 4096 validators in total will the committee size be reduced below TARGET_COMMITTEE_SIZE
. With so few validators, the system would be insecure in any case.
For further discussion and an explanation of how the value of TARGET_COMMITTEE_SIZE
was set, see the section on committees.
MAX_VALIDATORS_PER_COMMITTEE
This is just used for sizing some data structures, and is not particularly interesting. Reaching this limit would imply over 4 million active validators, staked with a total of 128 million Ether, which exceeds the total supply today.
SHUFFLE_ROUND_COUNT
The beacon chain implements a rather interesting way of shuffling validators in order to select committees, called the "swap-or-not shuffle". This shuffle proceeds in rounds, and the degree of shuffling is determined by the number of rounds, SHUFFLE_ROUND_COUNT
. The time taken to shuffle is linear in the number of rounds, so for light-weight, non-mainnet configurations, the number of rounds can be reduced.
The value 90 was introduced in Vitalik's initial commit without explanation. The original paper describing the shuffling technique seems to suggest that a cryptographically safe number of rounds is . With 90 rounds, then, we should be good for shuffling 3.3 million validators, which is close to the maximum number possible (given the Ether supply).
Hysteresis parameters
Name | Value |
---|---|
HYSTERESIS_QUOTIENT |
uint64(4) |
HYSTERESIS_DOWNWARD_MULTIPLIER |
uint64(1) |
HYSTERESIS_UPWARD_MULTIPLIER |
uint64(5) |
The parameters prefixed HYSTERESIS_
control the way that effective balance is changed (see EFFECTIVE_BALANCE_INCREMENT
). As described there, the effective balance of a validator follows changes to the actual balance in a step-wise way, with hysteresis applied. This ensures that the effective balance does not change often.
The original hysteresis design had an unintended effect that might have encouraged stakers to over-deposit or make multiple deposits in order to maintain a balance above 32 Ether at all times. If a validator's balance were to drop below 32 Ether soon after depositing, however briefly, the effective balance would have immediately dropped to 31 Ether and taken a long time to recover. This would have resulted in a 3% reduction in rewards for a period.
This problem was addressed by making the hysteresis configurable via these parameters. Specifically, these settings mean:
- if a validators' balance falls 0.25 Ether below its effective balance, then its effective balance is reduced by 1 Ether
- if a validator's balance rises 1.25 Ether above its effective balance, then its effective balance is increased by 1 Ether
These calculations are done in process_effective_balance_updates()
during end of epoch processing.
Gwei values
Name | Value |
---|---|
MIN_DEPOSIT_AMOUNT |
Gwei(2**0 * 10**9) (= 1,000,000,000) |
MAX_EFFECTIVE_BALANCE |
Gwei(2**5 * 10**9) (= 32,000,000,000) |
EFFECTIVE_BALANCE_INCREMENT |
Gwei(2**0 * 10**9) (= 1,000,000,000) |
MIN_DEPOSIT_AMOUNT
MIN_DEPOSIT_AMOUNT
is not actually used anywhere within the beacon chain specification document. Rather, it is enforced in the deposit contract that was deployed to the Ethereum 1 chain. Any amount less than this value sent to the deposit contract is reverted.
Allowing stakers to make deposits smaller than a full stake is useful for topping-up a validator's balance if its effective balance has dropped below 32 Ether, so as to maintain full productivity. However, this actually led to a vulnerability for some staking pools, involving the front-running of deposits. In some circumstances, a front-running attacker could change a genuine depositor's withdrawal credentials to their own.
MAX_EFFECTIVE_BALANCE
There is a concept of "effective balance" for validators: whatever a validator's total balance, its voting power is weighted by its effective balance, even if its actual balance is higher. Effective balance is also the amount on which all rewards, penalties, and slashings are calculated - it's used a lot in the protocol
The MAX_EFFECTIVE_BALANCE
is the highest effective balance that a validator can have: 32 Ether. Any balance above this is ignored. Note that this means that staking rewards don't compound in the usual case (unless a validator's effective balance somehow falls below 32 Ether, in which case rewards kind of compound).
There is a discussion in the Design Rationale of why 32 Ether was chosen as the staking amount. In short, we want enough validators to keep the chain both alive and secure under attack, but not so many that the message overhead on the network becomes too high.
EFFECTIVE_BALANCE_INCREMENT
Throughout the protocol, a quantity called "effective balance" is used instead of the validators' actual balances. Effective balance tracks the actual balance, with two differences: (1) effective balance is capped at MAX_EFFECTIVE_BALANCE
no matter how high the actual balance of a validator is, and (2) effective balance is much more granular - it changes only in steps of EFFECTIVE_BALANCE_INCREMENT
rather than Gwei
.
This discretisation of effective balance is intended to reduce the amount of hashing required when making state updates. The goal is to avoid having to re-calculate the hash tree root of validator records too often. Validators' actual balances, which change frequently, are stored as a contiguous list in BeaconState, outside of validators' records. Effective balances are stored inside validators' individual records, which are more costly to update (more hashing required). So we try to update effective balances relatively infrequently.
Effective balance is changed according to a process with hysteresis to avoid situations where it might change frequently. See HYSTERESIS_QUOTIENT
.
You can read more about effective balance in the Design Rationale and in this article.
Time parameters
Name | Value | Unit | Duration |
---|---|---|---|
MIN_ATTESTATION_INCLUSION_DELAY |
uint64(2**0) (= 1) |
slots | 12 seconds |
SLOTS_PER_EPOCH |
uint64(2**5) (= 32) |
slots | 6.4 minutes |
MIN_SEED_LOOKAHEAD |
uint64(2**0) (= 1) |
epochs | 6.4 minutes |
MAX_SEED_LOOKAHEAD |
uint64(2**2) (= 4) |
epochs | 25.6 minutes |
MIN_EPOCHS_TO_INACTIVITY_PENALTY |
uint64(2**2) (= 4) |
epochs | 25.6 minutes |
EPOCHS_PER_ETH1_VOTING_PERIOD |
uint64(2**6) (= 64) |
epochs | ~6.8 hours |
SLOTS_PER_HISTORICAL_ROOT |
uint64(2**13) (= 8,192) |
slots | ~27 hours |
MIN_ATTESTATION_INCLUSION_DELAY
A design goal of Ethereum 2.0 is not to heavily disadvantage validators that are running on lower-spec systems, or, conversely, to reduce any advantage gained by running on high-spec systems.
One aspect of performance is network bandwidth. When a validator becomes the block proposer, it needs to gather attestations from the rest of its committee. On a low-bandwidth link, this takes longer, and could result in the proposer not being able to include as many past attestations as other better-connected validators might, thus receiving lower rewards.
MIN_ATTESTATION_INCLUSION_DELAY
was an attempt to "level the playing field" by setting a minimum number of slots before an attestation can be included in a beacon block. It was originally set at 4, with a 6 second slot time, allowing 24 seconds for attestations to propagate around the network.
It was later set to one – attestations are included as early as possible – and, now that we plan to crosslink shards every slot, this is the only value that makes sense. So MIN_ATTESTATION_INCLUSION_DELAY
exists today as a kind of relic of the earlier design.
The current slot time of 12 seconds is assumed to allow sufficient time for attestations to propagate and be aggregated sufficiently within one slot.
SLOTS_PER_EPOCH
We currently have 12 second slots and 32 slot epochs. In earlier designs slots were six seconds and there were 64 slots per epoch. So the time between epoch boundaries was unchanged when slots were lengthened.
The choice of 32 slots per epoch is a trade-off between time to finality (we need two epochs to finalise, so we prefer to keep them as short as we can) and being as certain as possible that at least one honest proposer per epoch will make a block to update the RANDAO (for which we prefer longer epochs).
In addition, epoch boundaries are where the heaviest part of the beacon chain state-transition calculation occurs, so that's another reason for not having them too close together.
Since every validator attests one every epoch, there is an interplay between the number of slots per epoch, the number of committees per slot, committee sizes, and the total number of validators.
MIN_SEED_LOOKAHEAD
A random seed is used to select all the committees and proposers for an epoch. During each epoch, the beacon chain accumulates randomness from proposers via the RANDAO and stores it. The seed for the current epoch is based on the RANDAO output from the epoch MIN_SEED_LOOKAHEAD
+
1
ago. With MIN_SEED_LOOKAHEAD
set to one, the effect is that we can know the seed for the current epoch and the next epoch, but not beyond, since the next-but-one epoch depends on randomness from the current epoch that hasn't been accumulated yet.
This mechanism is designed to allow sufficient time for committee members to find each other on the peer-to-peer network, and in future to sync up any shard data they need. But preventing committee makeup being known too far ahead limits the opportunity for coordinated collusion between validators.
MAX_SEED_LOOKAHEAD
The above notwithstanding, if an attacker has a large proportion of the stake, or is, for example, able to DoS block proposers for a while, then it might be possible for the attacker to predict the output of the RANDAO further ahead than MIN_SEED_LOOKAHEAD
would normally allow. This might enable the attacker to manipulate committee memberships to their advantage by performing well-timed exits and activations of their validators.
To prevent this, we assume a maximum feasible lookahead that an attacker might achieve (MAX_SEED_LOOKAHEAD
) and delay all activations and exits by this amount, which allows new randomness to come in via block proposals from honest validators. With MAX_SEED_LOOKAHEAD
set to 4, if only 10% of validators are online and honest, then the chance that an attacker can succeed in forecasting the seed beyond (MAX_SEED_LOOKAHEAD
-
MIN_SEED_LOOKAHEAD
) = 3 epochs is , which is about 1 in 25,000.
MIN_EPOCHS_TO_INACTIVITY_PENALTY
The inactivity penalty is discussed below. This parameter sets the length of time until it kicks in. If the last finalised epoch is longer ago than MIN_EPOCHS_TO_INACTIVITY_PENALTY
, then the beacon chain starts operating in "leak" mode. In this mode, participating validators no longer get rewarded, and validators that are not participating get penalised.
EPOCHS_PER_ETH1_VOTING_PERIOD
In order to safely onboard new validators, the beacon chain needs to take a view on what the Eth1 chain looks like. This is done by collecting votes from beacon block proposers - they are expected to consult an available Eth1 client in order to construct their vote.
EPOCHS_PER_ETH1_VOTING_PERIOD
*
SLOTS_PER_EPOCH
is the total number of votes for Eth1 blocks that are collected. As soon as half of this number of votes are for the same Eth1 block, that block is adopted by the beacon chain and deposit processing can continue.
Rules for how validators select the right block to vote for are set out in the validator guide. ETH1_FOLLOW_DISTANCE
is the (approximate) minimum depth of block that can be considered.
This parameter was increased from 32 to 64 epochs for the beacon chain mainnet. This increase is intended to allow devs more time to respond if there is any trouble on the Eth1 chain, in addition to the eight hours grace provided by ETH1_FOLLOW_DISTANCE
.
For a detailed analysis of these parameters, see this article.
SLOTS_PER_HISTORICAL_ROOT
There have been several redesigns of the way the beacon chain stores its past history. The current design is a double batched accumulator. The block root and state root for every slot are stored in the state for SLOTS_PER_HISTORICAL_ROOT
slots. When that list is full, both lists are Merkleized into a single Merkle root, which is added to the ever-growing state.historical_roots
list.
State list lengths
The following parameters set the sizes of some lists in the beacon chain state. Some lists have natural sizes, others such as the validator registry need an explicit maximum size to guide SSZ serialisation.
Name | Value | Unit | Duration |
---|---|---|---|
EPOCHS_PER_HISTORICAL_VECTOR |
uint64(2**16) (= 65,536) |
epochs | ~0.8 years |
EPOCHS_PER_SLASHINGS_VECTOR |
uint64(2**13) (= 8,192) |
epochs | ~36 days |
HISTORICAL_ROOTS_LIMIT |
uint64(2**24) (= 16,777,216) |
historical roots | ~52,262 years |
VALIDATOR_REGISTRY_LIMIT |
uint64(2**40) (= 1,099,511,627,776) |
validators |
EPOCHS_PER_HISTORICAL_VECTOR
This is the number of epochs of previous RANDAO mixes that are stored (one per epoch). Having access to past randao mixes allows historical shufflings to be recalculated. Since Validator records keep track of the activation and exit epochs of all past validators, we can thus reconstitute past committees as far back as we have the RANDAO values. This information can be used for slashing long-past attestations, for example. It is not clear how the value of this parameter was decided.
EPOCHS_PER_SLASHINGS_VECTOR
In the epoch in which a misbehaving validator is slashed, its effective balance is added to an accumulator in the state. In this way, the state.slashings
list tracks the total effective balance of all validators slashed during the last EPOCHS_PER_SLASHINGS_VECTOR
epochs.
At a time EPOCHS_PER_SLASHINGS_VECTOR
//
2
after being slashed, a further penalty is applied to the slashed validator, based on the total amount of value slashed during the 4096 epochs before and the 4096 epochs after it was originally slashed.
The idea of this is to disproportionately punish coordinated attacks, in which many validators break the slashing conditions around the same time, while only lightly penalising validators that get slashed by making a mistake. Early designs for Eth2 would always slash a validator's entire deposit.
See also PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
.
HISTORICAL_ROOTS_LIMIT
Every SLOTS_PER_HISTORICAL_ROOT
slots, the list of block roots and the list of state roots in the beacon state are Merkleized and added to state.historical_roots
list. Although state.historical_roots
is in principle unbounded, all SSZ lists must have maximum sizes specified. The size HISTORICAL_ROOTS_LIMIT
will be fine for the next few millennia, after which it will be somebody else's problem. The list grows at less than 10 KB per year.
Storing past roots like this allows Merkle proofs to be constructed about anything in the beacon chain's history if required.
VALIDATOR_REGISTRY_LIMIT
Every time the Eth1 deposit contract processes a deposit from a new validator (as identified by its public key), a new entry is appended to the state.validators
list.
In the current design, validators are never removed from this list, even after exiting from being a validator. This is largely because there is nowhere yet to send a validator's remaining deposit and staking rewards, so they continue to need to be tracked in the beacon chain.
The maximum length of this list is VALIDATOR_REGISTRY_LIMIT
, which is one trillion, so we ought to be OK for a while, especially given that the minimum deposit amount is 1 Ether.
Rewards and penalties
Name | Value |
---|---|
BASE_REWARD_FACTOR |
uint64(2**6) (= 64) |
WHISTLEBLOWER_REWARD_QUOTIENT |
uint64(2**9) (= 512) |
PROPOSER_REWARD_QUOTIENT |
uint64(2**3) (= 8) |
INACTIVITY_PENALTY_QUOTIENT |
uint64(2**26) (= 67,108,864) |
MIN_SLASHING_PENALTY_QUOTIENT |
uint64(2**7) (= 128) |
PROPORTIONAL_SLASHING_MULTIPLIER |
uint64(1) |
INACTIVITY_PENALTY_QUOTIENT_ALTAIR |
uint64(3 * 2**24) (= 50,331,648) |
MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR |
uint64(2**6) (= 64) |
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR |
uint64(2) |
Note that there are similar constants with different values here, one version with an _ALTAIR
suffix. This is explained in the specs repo as follows:
Variables are not replaced but extended with forks. This is to support syncing from one state to another over a fork boundary, without hot-swapping a config. Instead, for forks that introduce changes in a variable, the variable name is suffixed with the fork name.
So, the unsuffixed versions are the Phase 0 values, and the _ALTAIR
suffixed versions are the values that apply to the current Altair fork.
BASE_REWARD_FACTOR
This is the big knob to turn to change the issuance rate of Eth2. Almost all validator rewards are calculated in terms of a "base reward per increment" which is formulated as,
EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR // integer_squareroot(get_total_active_balance(state))
Thus, the total validator rewards per epoch (the Eth2 issuance rate) could be tuned by increasing or decreasing BASE_REWARD_FACTOR
.
The exception is proposer rewards for including slashing reports in blocks. However, these are more than offset by the amount of stake burnt, so do not increase the overall issuance rate.
WHISTLEBLOWER_REWARD_QUOTIENT
One reward that is not tied to the base reward is the whistleblower reward. This is an amount awarded to the proposer of a block containing one or more proofs that a proposer or attester has violated a slashing condition. The whistleblower reward is set at of the effective balance of the slashed validator.
The whistleblower reward comes from new issuance of Ether on the beacon chain, but is more than offset by the Ether burned due to slashing penalties.
PROPOSER_REWARD_QUOTIENT
PROPOSER_REWARD_QUOTIENT
was removed in the Altair upgrade in favour of PROPOSER_WEIGHT
. It was used to apportion rewards between attesters and proposers when including attestations in blocks.
INACTIVITY_PENALTY_QUOTIENT_ALTAIR
This value supersedes INACTIVITY_PENALTY_QUOTIENT
.
If the beacon chain hasn't finalised a checkpoint for longer than MIN_EPOCHS_TO_INACTIVITY_PENALTY
epochs, then it enters "leak" mode. In this mode, any validator that does not vote (or votes for an incorrect target) is penalised an amount each epoch of (effective_balance * inactivity_score) // (
INACTIVITY_SCORE_BIAS
*
INACTIVITY_PENALTY_QUOTIENT_ALTAIR
)
.
In Altair, inactivity_score
is a per-validator quantity, whereas previously validators were penalised by a globally calculated amount when they missed a duty during a leak. See inactivity penalties for more on the rationale for this and how this score is calculated per validator.
During a leak, no validators receive rewards, and they continue to accrue the normal penalties when they fail to fulfil duties. In addition, for epochs in which validators do not make a correct, timely target vote, they receive a leak penalty.
To examine the effect of the leak on a single validator's balance, assume that during a period of inactivity leak (non-finalisation) the validator is completely offline. At each epoch, the offline validator will be penalised an amount , where is the number of epochs since the leak started, is the validator's effective balance, and is the prevailing INACTIVITY_PENALTY_QUOTIENT
.
The effective balance will remain constant for a while, by design, during which time the total amount of the penalty after epochs would be : the famous "quadratic leak". If were continuously variable, the penalty would satisfy , which can be solved to give . The actual behaviour is somewhere between these two since the effective balance decreases in a step-wise fashion.
In the continuous case, the INACTIVITY_PENALTY_QUOTIENT
, , is the square of the time it takes to reduce the balance of a non-participating validator to , or around 60.7% of its initial value. With the value of INACTIVITY_PENALTY_QUOTIENT_ALTAIR
at 3 * 2**24
, this equates to around seven thousand epochs, or 31.5 days.
The idea for the inactivity leak (aka the quadratic leak) was proposed in the original Casper FFG paper. The problem it addresses is that, if a large fraction of the validator set were to go offline at the same time, it would not be possible to continue finalising checkpoints, since a majority vote from validators representing 2/3 of the total stake is required for finalisation.
In order to recover, the inactivity leak gradually reduces the stakes of validators who are not making attestations until, eventually, the participating validators control 2/3 of the remaining stake. They can then begin to finalise checkpoints once again.
This inactivity penalty mechanism is designed to protect the chain long-term in the face of catastrophic events (sometimes referred to as the ability to survive World War III). The result might be that the beacon chain could permanently split into two independent chains either side of a network partition, and this is assumed to be a reasonable outcome for any problem that can't be fixed in a few weeks. In this sense, the beacon chain formally prioritises availability over consistency. (You can't have both.)
The value of INACTIVITY_PENALTY_QUOTIENT
was increased by a factor of four from 2**24
to 2**26
for the beacon chain launch, with the intention of penalising validators less severely in case of non-finalisation due to implementation problems in the early days. As it happens, there were no instances of non-finalisation during the eleven months of Phase 0 of the beacon chain.
The value was decreased by one quarter in the Altair upgrade from 2**26
to 3 * 2**24
as a step towards eventually setting it to its final value. Decreasing the inactivity penalty quotient speeds up recovery of finalisation in the event of an inactivity leak.
MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
When a validator is first convicted of a slashable offence, an initial penalty is applied. This is calculated as, validator.effective_balance
//
MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
.
Thus, the initial slashing penalty is between 0.25 Ether and 0.5 Ether depending on the validator's effective balance (which is between 16 and 32 Ether; note that effective balance is denominated in Gwei).
A further slashing penalty is applied later based on the total amount of balance slashed during a period of EPOCHS_PER_SLASHINGS_VECTOR
.
The value of MIN_SLASHING_PENALTY_QUOTIENT
was increased by a factor of four from 2**5
to 2**7
for the beacon chain launch, anticipating that unfamiliarity with the rules of Ethereum 2.0 staking was likely to result in some unwary users getting slashed. In the event, a total of 157 validators were slashed during Phase 0, all as a result of user error or misconfiguration as far as can be determined.
The value was halved in the Altair upgrade from 2**7
to 2**6
as a step towards eventually setting it to its final value of 2**5
.
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
When a validator has been slashed, a further penalty is later applied to the validator based on how many other validators were slashed during a window of size EPOCHS_PER_SLASHINGS_VECTOR
epochs centred on that slashing event (approximately 18 days before and after).
The proportion of the validator's remaining effective balance that will be subtracted is calculated as, PROPORTIONAL_SLASHING_MULTIPLIER
multiplied by the sum of the effective balances of the slashed validators in the window, divided by the total effective balance of all validators. The idea of this mechanism is to punish accidents lightly (in which only a small number of validators were slashed) and attacks heavily (where many validators coordinated to double vote).
To finalise conflicting checkpoints, at least a third of the balance must have voted for both. That's why the "natural" setting of PROPORTIONAL_SLASHING_MULTIPLIER
is three: in the event of an attack that finalises conflicting checkpoints, the attackers lose their entire stake. This provides "the maximal minimum accountable safety margin".
However, for the initial stage of the beacon chain, Phase 0, PROPORTIONAL_SLASHING_MULTIPLIER
was set to one, and increased to two at the Altair upgrade. These lower values provide some insurance against client bugs that might cause mass slashings in the early days. It will eventually be increased to its final value of three in a later upgrade.
Max operations per block
Name | Value |
---|---|
MAX_PROPOSER_SLASHINGS |
2**4 (= 16) |
MAX_ATTESTER_SLASHINGS |
2**1 (= 2) |
MAX_ATTESTATIONS |
2**7 (= 128) |
MAX_DEPOSITS |
2**4 (= 16) |
MAX_VOLUNTARY_EXITS |
2**4 (= 16) |
These parameters are used to size lists in the beacon block bodies for the purposes of SSZ serialisation, as well as constraining the maximum size of beacon blocks so that they can propagate efficiently, and avoid DoS attacks.
Some comments on the chosen values:
- I have suggested elsewhere reducing
MAX_DEPOSITS
from sixteen to one to ensure that more validators must process deposits, which encourages them to run Eth1 clients. - At first sight, there looks to be a disparity between the number of proposer slashings and the number of attester slashings that may be included in a block. But note that an attester slashing (a) can be much larger than a proposer slashing, and (b) can result in many more validators getting slashed than a proposer slashing.
MAX_ATTESTATIONS
is double the value ofMAX_COMMITTEES_PER_SLOT
. This allows there to be an empty slot (with no block proposal), yet still include all the attestations for the empty slot in the next slot. Since, ideally, each committee produces a single aggregate attestation, a block can hold two slots' worth of aggregate attestations.
Sync committee
Name | Value | Unit | Duration |
---|---|---|---|
SYNC_COMMITTEE_SIZE |
uint64(2**9) (= 512) |
Validators | |
EPOCHS_PER_SYNC_COMMITTEE_PERIOD |
uint64(2**8) (= 256) |
epochs | ~27 hours |
Sync committees were introduced by the Altair upgrade to allow light clients to quickly and trustlessly determine the head of the beacon chain.
Why did we need a new committee type? Couldn't this be built on top of existing committees, say committees 0 to 3 at a slot? After all, voting for the head of the chain is already one of their duties. The reason is that it is important for reducing the load on light clients that sync committees do not change very often. Standard committees change every slot; we need something much longer lived here.
Only a single sync committee is active at any one time, and contains a randomly selected subset of size SYNC_COMMITTEE_SIZE
of the total validator set.
A sync committee does its duties (and receives rewards for doing so) for only EPOCHS_PER_SYNC_COMMITTEE_PERIOD
epochs until the next committee takes over.
With 262,144 validators (), the expected time between being selected for sync committee duty is over 19 months. The probability of being in the current sync committee would be 1/512 per validator.
SYNC_COMMITTEE_SIZE
is a trade-off between security (ensuring that enough honest validators are always present) and efficiency for light clients (ensuring that they do not have to handle too much computation). The value 512 is conservative in terms of safety. It would be catastrophic for trustless bridges to other protocols, for example, if a sync committee voted in an invalid block.
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
is around a day, and again is a trade-off between security (short enough that it's hard for an attacker to find and corrupt committee members) and efficiency (reducing the data load on light clients).