# EIP-4844 -- The Beacon Chain **Notice**: This document is a work-in-progress for researchers and implementers. ## Table of contents - [Introduction](#introduction) - [Custom types](#custom-types) - [Constants](#constants) - [Preset](#preset) - [Trusted setup](#trusted-setup) - [Configuration](#configuration) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) - [Helper functions](#helper-functions) - [Misc](#misc) - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzgs_against_transactions`](#verify_kzgs_against_transactions) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Block processing](#block-processing) - [Blob KZGs](#blob-kzgs) - [Testing](#testing) ## Introduction This upgrade adds transaction execution to the beacon chain as part of Bellatrix upgrade. Additionally, this upgrade introduces the following minor changes: * Penalty parameter updates to their planned maximally punitive values ## Custom types | Name | SSZ equivalent | Description | | - | - | - | | `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | | `Blob` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | | | `VersionedHash` | `Bytes32` | | | `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | ## Constants | Name | Value | | - | - | | `BLOB_TX_TYPE` | `uint8(0x05)` | | `FIELD_ELEMENTS_PER_BLOB` | `4096` | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | ## Preset ### Trusted setup The trusted setup is part of the preset: during testing a `minimal` insecure variant may be used, but reusing the `mainnet` settings in public networks is a critical security requirement. | Name | Value | | - | - | | `KZG_SETUP_G2` | `Vector[G2Point, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | | `KZG_SETUP_LAGRANGE` | `Vector[BLSCommitment, FIELD_ELEMENTS_PER_BLOB]`, contents TBD | ## Configuration ## Containers ### Extended containers #### `BeaconBlockBody` Note: `BeaconBlock` and `SignedBeaconBlock` types are updated indirectly. ```python 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 # Execution execution_payload: ExecutionPayload blob_kzgs: List[KZGCommitment, MAX_OBJECT_LIST_SIZE] # [New in EIP-4844] ``` ## Helper functions ### Misc #### `tx_peek_blob_versioned_hashes` This function retrieves the hashes from the `SignedBlobTransaction` as defined in EIP-4844, using SSZ offsets. Offsets are little-endian `uint32` values, as defined in the [SSZ specification](../../ssz/simple-serialize.md). ```python def tx_peek_blob_versioned_hashes(opaque_tx: Transaction) -> Sequence[VersionedHash]: assert opaque_tx[0] == BLOB_TX_TYPE message_offset = 1 + uint32.decode_bytes(opaque_tx[1:5]) # field offset: 32 + 8 + 32 + 32 + 8 + 4 + 32 + 4 + 4 = 156 blob_versioned_hashes_offset = uint32.decode_bytes(opaque_tx[message_offset+156:message_offset+160]) return [VersionedHash(opaque_tx[x:x+32]) for x in range(blob_versioned_hashes_offset, len(opaque_tx), 32)] ``` #### `verify_kzgs_against_transactions` ```python def verify_kzgs_against_transactions(transactions: Sequence[Transaction], blob_kzgs: Sequence[KZGCommitment]) -> bool: all_versioned_hashes = [] for tx in transactions: if opaque_tx[0] == BLOB_TX_TYPE: all_versioned_hashes.extend(tx_peek_blob_versioned_hashes(tx)) return all_versioned_hashes == [ kzg_to_versioned_hash(kzg) for kzg in blob_kzgs ] ``` ## Beacon chain state transition function ### Block processing ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) if is_execution_enabled(state, block.body): process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) process_blob_kzgs(state, block.body) # [New in EIP-4844] ``` #### Blob KZGs ```python def process_blob_kzgs(body: BeaconBlockBody): assert verify_kzgs_against_transactions(body.execution_payload.transactions, body.blob_kzgs) # TODO do we want to buffer the kzg commitments in the BeaconState, like in the full sharding design? # This could make a proof to any particular blob commitment more efficient, # but the buffer structure is also likely to change with full sharding. ``` ## Testing *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. The `BeaconState` initialization is unchanged, except for the use of the updated `eip4844.BeaconBlockBody` type when initializing the first body-root: ```python state.latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ```