Skip to content

EIP-8025 -- Networking

This document contains the networking specifications for EIP-8025.

Note: This specification is built upon Gloas and imports proof types from beacon-chain.md.

EIP-8025 proofs propagate exclusively through gossip. No EIP-8025-specific Req/Resp protocol is defined.

Table of contents

Constants

Type-specific SSZ bounds

Name Value
MAX_SIGNED_EXECUTION_PROOF_ENVELOPE_SIZE Uint64(4194449) (= ~4 MiB)

Helpers

Modified Seen

@dataclass
class Seen:
    proposer_slots: Set[Tuple[Slot, ValidatorIndex]]
    aggregator_epochs: Set[Tuple[Epoch, ValidatorIndex]]
    aggregate_data_roots: Dict[Tuple[Root, CommitteeIndex], Set[Tuple[bool, ...]]]
    voluntary_exit_indices: Set[ValidatorIndex]
    proposer_slashing_indices: Set[ValidatorIndex]
    attester_slashing_indices: Set[ValidatorIndex]
    attestation_validator_epochs: Set[Tuple[Epoch, ValidatorIndex]]
    sync_contribution_aggregator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]]
    sync_contribution_data: Dict[Tuple[Slot, Root, Uint64], Set[Tuple[bool, ...]]]
    sync_message_validator_slots: Set[Tuple[Slot, ValidatorIndex, Uint64]]
    bls_to_execution_change_indices: Set[ValidatorIndex]
    data_column_sidecar_tuples: Set[Tuple[Root, ColumnIndex]]
    execution_payloads: Dict[Hash32, ExecutionPayload]
    execution_payload_envelopes: Set[Tuple[Root, BuilderIndex]]
    payload_attestation_validators: Set[Tuple[Slot, ValidatorIndex]]
    execution_payload_bids: Set[Tuple[Slot, Hash32, Root, BuilderIndex]]
    best_execution_payload_bid: Dict[Tuple[Slot, Hash32, Root], Gwei]
    proposer_preferences: Dict[Tuple[Slot, Root], ProposerPreferences]
    # [New in EIP8025]
    execution_proof_roots: Dict[Root, Set[Root]]
    # [New in EIP8025]
    execution_proof_provers: Set[Tuple[Root, ProofType, ValidatorIndex]]

The gossip domain: gossipsub

Topics and messages

Global topics

New execution_proof

This topic is used to propagate SignedExecutionProofEnvelope messages.

def validate_execution_proof_gossip(
    seen: Seen,
    store: Store,
    signed_proof_envelope: SignedExecutionProofEnvelope,
    proof_engine: ProofEngine,
) -> None:
    """
    Validate a SignedExecutionProofEnvelope for gossip propagation.
    Raises GossipIgnore or GossipReject on validation failure.
    """
    proof_envelope = signed_proof_envelope.message
    beacon_block_root = proof_envelope.beacon_block_root
    proof_root = hash_tree_root(proof_envelope)

    # [IGNORE] The proof has not already been processed
    if proof_root in seen.execution_proof_roots.get(beacon_block_root, set()):
        raise GossipIgnore("execution proof has already been processed")

    # [IGNORE] This is the prover's first valid or invalid proof for this key
    validator_index = signed_proof_envelope.validator_index
    prover_key = (beacon_block_root, proof_envelope.proof_type, validator_index)
    if prover_key in seen.execution_proof_provers:
        raise GossipIgnore(
            "proof already seen from this prover for this beacon block and proof type"
        )

    # [IGNORE] The proof's beacon block has been seen
    if beacon_block_root not in store.blocks:
        raise GossipIgnore("execution proof's beacon block has not been seen")

    # [REJECT] The proof's beacon block has passed consensus validation
    if beacon_block_root not in store.block_states:
        raise GossipReject("execution proof's beacon block failed validation")

    state = store.block_states[beacon_block_root]

    # [IGNORE] The proof's execution payload is available
    if beacon_block_root not in store.payloads:
        raise GossipIgnore("execution proof's payload is unavailable")

    payload_envelope = store.payloads[beacon_block_root]

    # [IGNORE] No valid proof is known for this beacon block and proof type
    if proof_envelope.proof_type in store.execution_proofs.get(beacon_block_root, {}):
        raise GossipIgnore("verified proof already known for this beacon block and proof type")

    # [REJECT] The execution proof envelope passes validation
    try:
        verify_execution_proof_envelope(
            state,
            signed_proof_envelope,
            payload_envelope,
        )
    except AssertionError:
        raise GossipReject("execution proof envelope is invalid") from None

    proof = get_execution_proof(
        state,
        proof_envelope,
        payload_envelope,
    )

    # Mark the authenticated proof and prover attempt as seen
    if beacon_block_root not in seen.execution_proof_roots:
        seen.execution_proof_roots[beacon_block_root] = set()
    seen.execution_proof_roots[beacon_block_root].add(proof_root)
    seen.execution_proof_provers.add(prover_key)

    # [REJECT] The execution proof is valid
    if not proof_engine.verify_execution_proof(proof):
        raise GossipReject("execution proof is invalid")

The discovery domain: discv5

ENR structure

Execution proof awareness

A new field is added to the ENR under the key eproof to facilitate discovery and peering between nodes that participate in execution-proof gossip.

Key Value
eproof Execution layer proof awareness, Uint8

A node is considered execution proof-aware if the eproof key is present and its value is not 0. An execution proof-aware node subscribes to the execution_proof gossip topic and implements its validation rules. Clients MAY prefer execution proof-aware nodes when selecting peers for execution-proof gossip.