--- eip: 8359 title: Beacon Block Reporting Field description: Adds a beacon block body field for validator client and setup reporting. author: hanniabu (@hanniabu), Luca Winter (@eth2353), Paul Harris (@rolfyone) discussions-to: https://ethereum-magicians.org/t/eip-8359-beacon-block-reporting-field/29224 status: Draft type: Standards Track category: Core created: 2026-07-31 --- ## Abstract This EIP adds a new 32-byte `reporting` field to the consensus-layer beacon block body. The field allows validators to report the CL client, EL client, validator setup type, and client agreement threshold used to verify the correctness of the chain. The field is informational only and does not impact consensus if this field contains missing or malformed data. ## Motivation Ethereum network resilience depends on client diversity across the consensus layer and execution layer. However, there is currently no reliable source of validator client usage data. Existing approaches have important shortcomings: * **Fingerprinting:** Attempts to infer client usage from block proposal behavior, but this can become inaccurate after client behavior changes or protocol upgrades. * **Network Crawling:** Measures reachable nodes rather than validator nodes, and can be affected by peer selection bias. * **Relay Data:** Depends on relay participation, which ePBS removes (would also need to convince them to share the data to be aggregated and there's incentive to underreport more profitable clients). * **Graffiti Watermark:** Uses proposal graffiti field to report CL/EL client but implementation isn't standardized, relies on there being enough room if a custom graffiti is set, doesn't account for multinode/DVT setups, and can't be extended to additional reporting. This EIP creates a dedicated, standardized, compact field for client reporting. The field is optional for validators to populate and may be disabled by node operators. The resulting data improves visibility into validator setups and network exposure to correlated client bugs. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174). ### Beacon block body change Beginning at `FORK_TIMESTAMP_OR_EPOCH`, the consensus-layer `BeaconBlockBody` container is extended with a new field: ```python class BeaconBlockBody(Container): ... graffiti: Bytes32 ... reporting: Bytes32 ``` The exact placement of `reporting` in `BeaconBlockBody` SHOULD be finalized in the consensus specifications. The field MUST be included in the SSZ serialization and hash tree root of the beacon block body. The `reporting` field is informational. Consensus clients MUST NOT reject a block based on the contents of this field. Any 32-byte value MUST be considered valid. ### Default value If a validator does not report client data, the field MUST be set to: ```text 0x0000000000000000000000000000000000000000000000000000000000000000 ``` A validator client MAY allow node operators to disable reporting. Reporting SHOULD be enabled by default. ### Encoding `reporting` is a 32-byte field encoded as follows: ```text byte 0 field version byte 1 setup and threshold bytes 2-15 client pairs bytes 16-31 reserved ``` #### Byte 0: field version ```text byte 0 [7:0] = field version ``` For this EIP, the initial version is: ```text 0x01 ``` A value of `0x00` means undefined or not reported. Future EIPs MAY define additional versions. #### Byte 1: setup and threshold ```text byte 1 [7:3] = setup byte 1 [2:0] = threshold ``` The `setup` value identifies the validator setup type and supports up to 32 setup options. The `threshold` value identifies the `M` value in an `M`-of-`N` agreement threshold used by a multi-node validator setup before signing or publishing the validator duty. Values `1` through `6` encode explicit `M` values, while `0` represents undefined and `7` represents other thresholds. For simple single-node setups where no multi-node threshold applies, `threshold` SHOULD be set to `1`. The threshold field is informational and does not define or enforce any slashing-protection, attestation, sync committee, block proposal, or signing behavior. #### Bytes 2-15: client pairs Each byte from byte 2 through byte 15 encodes one consensus-layer and execution-layer client pair. ```text high nibble [7:4] = consensus-layer client low nibble [3:0] = execution-layer client ``` This allows 14 client pairs to be reported, with up to 16 possible consensus-layer client options and 16 possible execution-layer client options. Unused client pair bytes SHOULD be set to `0x00`. A validator using a single CL/EL pair SHOULD encode that pair in byte 2 and set bytes 3 through 15 to `0x00`. A validator using multiple CL/EL pairs, such as in a multi-node, distributed validator, or remote signer setup, SHOULD encode each active pair in bytes 2 through 15. The ordering of reported pairs SHOULD be stable for a given validator configuration but has no consensus meaning. #### Bytes 16-31: reserved Bytes 16 through 31 are reserved for future use and SHOULD be set to zero for version `0x01`. Future versions MAY use these bytes for additional reporting, including but not limited to solo staker declaration. ### Reference registries The numerical values used for setup types, threshold types, consensus-layer clients, and execution-layer clients MUST be defined in stable registries. The following registry values are proposed for version `0x01`. These registries are expected to reside in the consensus specifications and be maintained alongside other consensus-layer constants. #### Setup registry | Value | Meaning | | ----- | --------- | | `0` | Undefined | | `1` | Unknown | | `2` | Other | | `3` | Simple | | `4` | Obol | | `5` | SSV | | `6` | Vero | | `7` | Vouch | Values `8` through `31` are unassigned. #### Threshold registry | Value | Meaning | | ----- | --------------------------- | | `0` | Undefined or not applicable | | `1` | 1-of-N | | `2` | 2-of-N | | `3` | 3-of-N | | `4` | 4-of-N | | `5` | 5-of-N | | `6` | 6-of-N | | `7` | Other | This registry intentionally encodes only `M`, not `N`, in order to fit within 3 bits. Future versions MAY define a different threshold encoding. #### Consensus-layer client registry | Value | Meaning | | ----- | ---------- | | `0` | Undefined | | `1` | Unknown | | `2` | Other | | `3` | Caplin | | `4` | Grandine | | `5` | Lighthouse | | `6` | Lodestar | | `7` | Nimbus | | `8` | Teku | | `9` | Prysm | Values `10` through `15` are unassigned. #### Execution-layer client registry | Value | Meaning | | ----- | --------------- | | `0` | Undefined | | `1` | Unknown | | `2` | Other | | `3` | Besu | | `4` | Erigon | | `5` | Ethrex | | `6` | Geth | | `7` | Nethermind | | `8` | Nimbus | | `9` | Reth | Values `10` through `15` are unassigned. ### Example Assume the following values: ```text field version: 1 setup: Vero threshold: 3 (3-of-N) client pairs: Teku + Nethermind Lodestar + Geth Nimbus + Nethermind Lighthouse + Besu ``` The resulting encoding is: ```text byte 0 = 00000001 = 0x01 byte 1 = 00110 011 = 0x33 byte 2 = 1000 0111 = 0x87 byte 3 = 0110 0110 = 0x66 byte 4 = 0111 0111 = 0x77 byte 5 = 0101 0011 = 0x53 bytes 6-15 = 0x00 bytes 16-31 = 0x00 ``` The full `reporting` value is: ```text 0x0133876677530000000000000000000000000000000000000000000000000000 ``` ## Rationale ### Dedicated field instead of graffiti The existing `graffiti` field is validator-controlled arbitrary data which has priority over client data watermarks. The watermarks also have no standardized truncating behavior and don't support setup types, thresholds, or optionality for future tracking (like solo staker declaration). A dedicated field gives the data a clear purpose and avoids competing with custom validator graffiti. ### 32 bytes A 32-byte field matches the size of the existing beacon block body `graffiti` field and is small enough to add minimal block size overhead. The initial version uses only the first 16 bytes, leaving the remaining 16 bytes reserved for future extensions. ### One byte per CL/EL pair Encoding each client pair in one byte provides a compact representation of up to 14 CL/EL combinations. The high nibble represents the consensus-layer client and the low nibble represents the execution-layer client. This is sufficient for currently known major clients while leaving values for `undefined`, `other`, and future assignments. ### Versioned encoding The first byte is a field version so the bytes can be reinterpreted without ambiguity. This is intended to support append-only registry updates and future reporting needs without requiring every registry addition to occur on fork cadence. ### Optional reporting The field is intended to improve aggregate network visibility, not to enforce correct client reporting. Validators MAY opt out by setting the field to zero. This avoids forcing operators to reveal information they prefer not to publish and avoids consensus complexity around validating off-chain client configuration. ### No consensus validation of truthfulness Consensus clients cannot generally verify that a validator truthfully reported its local client setup. Therefore, the protocol only defines the field format. It does not attempt to prove or enforce correctness of the report. ## Backwards Compatibility This EIP changes the SSZ container for `BeaconBlockBody` and is therefore not backwards compatible with pre-fork consensus clients. The change MUST be activated only as part of a consensus-layer network upgrade. Pre-fork blocks MUST use the previous `BeaconBlockBody` container. Post-fork blocks MUST use the updated container containing `reporting`. The field does not change the beacon state transition other than the block body schema change. Existing validator behavior remains valid if `reporting` is set to zero. ## Test Cases Consensus tests SHOULD include at least the following cases: 1. A post-fork block with `reporting` set to all zeroes is valid. 2. A post-fork block with `reporting` version `0x01` and all reserved bytes zero is valid. 3. A post-fork block with unknown setup, threshold, CL client, or EL client values is valid. 4. A post-fork block with non-zero bytes 16 through 31 for version `0x01` is valid. 5. A pre-fork block using the pre-fork `BeaconBlockBody` schema remains valid. 6. A post-fork block using the pre-fork `BeaconBlockBody` schema is invalid. 7. SSZ hash tree root test vectors are provided for post-fork beacon block bodies with: * all-zero `reporting` * a single CL/EL pair * multiple CL/EL pairs * unknown registry values * non-zero reserved bytes, if permitted ## Reference Implementation The following pseudocode illustrates version `0x01` encoding: ```python def encode_reporting( version: int, setup: int, threshold: int, client_pairs: list[tuple[int, int]], ) -> bytes: assert 0 <= version <= 255 assert 0 <= setup <= 31 assert 0 <= threshold <= 7 assert len(client_pairs) <= 14 out = bytearray(32) out[0] = version out[1] = (setup << 3) | threshold for i, (cl_client, el_client) in enumerate(client_pairs): assert 0 <= cl_client <= 15 assert 0 <= el_client <= 15 out[2 + i] = (cl_client << 4) | el_client return bytes(out) ``` Example: ```python client_data = encode_reporting( version=1, setup=6, threshold=3, client_pairs=[ (8, 7), # Teku + Nethermind (6, 6), # Lodestar + Geth (7, 7), # Nimbus + Nethermind (5, 3), # Lighthouse + Besu ], ) assert client_data.hex() == ( "01338766775300000000000000000000" "00000000000000000000000000000000" ) ``` ## Security Considerations ### Privacy Publishing client setup information may reveal operational details about validators. This risk is reduced by omitting client version numbers and allowing validators to disable reporting. However, validators using uncommon client combinations, uncommon setup types, or rare threshold configurations may still become more identifiable. Clients SHOULD provide a configuration option to disable reporting. Clients MAY also provide separate controls for reporting setup type and client pairs. ### Spoofing The protocol does not verify whether reported client data is truthful. Validators can intentionally misreport their setup or client pairings. This EIP is therefore not suitable for rewards, penalties, fork-choice weighting, slashing logic, or any mechanism that assumes reported client data is correct. The field is intended only for aggregate observability. ### Stale data Because this field is reported only when a validator proposes a block, aggregate data updates slowly. A validator's reported client setup may become stale if the operator changes clients before the validator proposes again. Consumers of this data SHOULD treat reports as time-dependent observations and SHOULD account for validator proposal frequency when estimating network-wide client distribution. ### Registry governance The setup and client registries require stable value assignment. Poorly managed registry changes could create ambiguity for data consumers. New registry values for a current version MAY be added. Existing registry values for a current version MUST NOT be reassigned to different meanings. ### Reserved bytes For version `0x01`, reserved bytes are intended for future use. Implementers SHOULD set bytes 16 through 31 to zero. The final specification should decide whether non-zero reserved bytes are consensus-invalid or merely ignored by data consumers. Making them consensus-invalid provides stricter canonical encoding, while allowing arbitrary values reduces the chance of rejecting blocks due to non-critical reporting mistakes. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).