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 and RFC 8174.
Beacon block body change
Beginning at FORK_TIMESTAMP_OR_EPOCH, the consensus-layer BeaconBlockBody container is extended with a new field:
class BeaconBlockBody(Container):
...
graffiti: Bytes32
...
reporting: Bytes32The 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:
0x0000000000000000000000000000000000000000000000000000000000000000A 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:
byte 0 field version
byte 1 setup and threshold
bytes 2-15 client pairs
bytes 16-31 reservedByte 0: field version
byte 0 [7:0] = field versionFor this EIP, the initial version is:
0x01A value of 0x00 means undefined or not reported.
Future EIPs MAY define additional versions.
Byte 1: setup and threshold
byte 1 [7:3] = setup
byte 1 [2:0] = thresholdThe 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.
high nibble [7:4] = consensus-layer client
low nibble [3:0] = execution-layer clientThis 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:
field version: 1
setup: Vero
threshold: 3 (3-of-N)
client pairs:
Teku + Nethermind
Lodestar + Geth
Nimbus + Nethermind
Lighthouse + BesuThe resulting encoding is:
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 = 0x00The full reporting value is:
0x0133876677530000000000000000000000000000000000000000000000000000Rationale
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:
-
A post-fork block with
reportingset to all zeroes is valid. -
A post-fork block with
reportingversion0x01and all reserved bytes zero is valid. -
A post-fork block with unknown setup, threshold, CL client, or EL client values is valid.
-
A post-fork block with non-zero bytes 16 through 31 for version
0x01is valid. -
A pre-fork block using the pre-fork
BeaconBlockBodyschema remains valid. -
A post-fork block using the pre-fork
BeaconBlockBodyschema is invalid. -
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
- all-zero
Reference Implementation
The following pseudocode illustrates version 0x01 encoding:
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:
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.
