Part 3: Annotated Specification
class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data # Eth1 data vote graffiti: Bytes32 # Arbitrary data # Operations proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] attestations: List[Attestation, MAX_ATTESTATIONS] deposits: List[Deposit, MAX_DEPOSITS] voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] sync_aggregate: SyncAggregate # [New in Altair] # Execution execution_payload: ExecutionPayload # [New in Bellatrix] # Capella operations bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella]
The two fundamental data structures for nodes are the
BeaconBlock and the
BeaconBlock is how the leader (the chosen proposer in a slot) communicates network updates to all the other validators, and those validators update their own
BeaconState by applying
BeaconBlocks. The idea is that (eventually) all validators on the network come to agree on the same
Validators are randomly selected to propose beacon blocks, and there ought to be exactly one beacon block per slot if things are running correctly. If a validator is offline, or misses its slot, or proposes an invalid block, or has its block orphaned, then a slot can be empty.
The following objects are always present in a valid beacon block.
randao_reveal: the block is invalid if the RANDAO reveal does not verify correctly against the proposer's public key. This is the block proposer's contribution to the beacon chain's randomness. The proposer generates it by signing the current epoch number (combined with
DOMAIN_RANDAO) with its private key. To the best of anyone's knowledge, the result is indistinguishable from random. This gets mixed into the beacon state RANDAO.
- See Eth1Data for
eth1_data. In principle, this is mandatory, but it is not checked, and there is no penalty for making it up.
graffitiis left free for the proposer to insert whatever data it wishes. It has no protocol level significance. It can be left as zero; most clients set the client name and version string as their own default graffiti value.
sync_aggregateis a record of which validators in the current sync committee voted for the chain head in the previous slot.
execution_payloadis what was known as an Eth1 block pre-Merge. Ethereum transactions are now included within beacon blocks in the form of an
Deposits are a special case. They are mandatory only if there are pending deposits to be processed. There is no explicit reward for including deposits, except that a block is invalid without any that ought to be there.
deposits: if the block does not contain either all the outstanding
MAX_DEPOSITSof them in deposit order, then it is invalid.
Including any of the remaining objects is optional. They are handled, if present, in the
The proposer earns rewards for including any of the following. Rewards for attestations and sync aggregates are available every slot. Slashings, however, are very rare.
proposer_slashings: up to
ProposerSlashingobjects may be included.
attester_slashings: up to
AttesterSlashingobjects may be included.
attestations: up to
Attestationobjects may be included. The block proposer is incentivised to include well-packed aggregate attestations, as it receives a micro reward for each unique attestation. In a perfect world, with perfectly aggregated attestations,
MAX_ATTESTATIONSwould be equal to
MAX_COMMITTEES_PER_SLOT; in our configuration it is double. This provides capacity in blocks to catch up with attestations after skip slots, and also room to include some imperfectly aggregated attestations.
Including voluntary exits and BLS to execution changes is optional, and there are no explicit rewards for doing so.
voluntary_exits: up to
SignedVoluntaryExitobjects may be included.
bls_to_execution_changes: up to
SignedBLSToExecutionChangeobjects may be included.
class BeaconBlock(Container): slot: Slot proposer_index: ValidatorIndex parent_root: Root state_root: Root body: BeaconBlockBody
BeaconBlock just adds some blockchain paraphernalia to
BeaconBlockBody. It is identical to
BeaconBlockHeader, except that the
body_root is replaced by the actual block
slot is the slot the block is proposed for.
proposer_index was added to avoid a potential DoS vector, and to allow clients without full access to the state to still know useful things.
parent_root is used to make sure that this block is a direct child of the last block we processed.
In order to calculate
state_root, the proposer is expected to run the state transition with the block before propagating it. After the beacon node has processed the block, the state roots are compared to ensure they match. This is the mechanism for tying the whole system together and making sure that all validators and beacon nodes are always working off the same version of state (in the absence of short-term forks).
If any of these is incorrect, then the block is invalid with respect to the current beacon state and will be ignored.