Refactor EIP8025 proof engine and p2p interface#5055
Refactor EIP8025 proof engine and p2p interface#5055frisitano wants to merge 2 commits intoethereum:masterfrom
Conversation
| parent_beacon_block_root=state.latest_block_header.parent_root, | ||
| execution_requests=body.execution_requests, | ||
| ) | ||
| ) |
There was a problem hiding this comment.
The proof engine call is deliberately non-asserting. Consensus correctness does not depend on the proof engine's state — notify_new_payload is a best-effort notification to allow the engine to begin proof verification or caching ahead of receiving gossip proofs.
| new_payload_request_header: NewPayloadRequestHeader, | ||
| ) -> bool: | ||
| new_payload_request: NewPayloadRequest, | ||
| ) -> None: |
There was a problem hiding this comment.
Return type is None — the proof engine is not expected to return a result synchronously. Proof outcomes are delivered asynchronously via SSE events and the verify_execution_proof path.
| - _[IGNORE]_ The proof has not already been processed -- i.e. | ||
| `hash_tree_root(proof)` has not been seen before. |
There was a problem hiding this comment.
Placed first as the cheapest deduplication check — avoids redundant signature verification and state lookups for proofs we have already processed.
| - _[IGNORE]_ The validator has not previously sent an invalid proof -- i.e. no | ||
| *invalid* proof from the public key associated with | ||
| `signed_execution_proof.validator_index` has been received. |
There was a problem hiding this comment.
Keyed on public key rather than validator_index because validator indices are epoch-dependent and can be reused after exits. Blacklisting by public key is stable across the validator lifecycle.
| ( | ||
| block_root: Root | ||
| slot: Slot | ||
| proof_types: List[ProofType, MAX_EXECUTION_PROOFS_PER_PAYLOAD] |
There was a problem hiding this comment.
proof_types is a dynamic capability advertisement rather than a protocol constant. A client advertises the proof types it currently supports at the point of request, allowing peers to make informed decisions during sync and peer selection. Critically, this means new proof types can be rolled out and adopted by clients without requiring a hard fork or coordinated client release — a client that understands a new proof type simply starts advertising it.
There was a problem hiding this comment.
This may be problematic regarding consensus so I would encourage discussion on this.
| ( | ||
| start_slot: Slot | ||
| count: uint64 | ||
| proof_filters: List[ProofByRootIdentifier, MAX_REQUEST_BLOCKS_DENEB] |
There was a problem hiding this comment.
Mirrors the ProofByRootIdentifier filtering already present in ExecutionProofsByRoot. Useful when a client has partially synced proofs for a range and only needs specific missing proof types for specific blocks, avoiding redundant data transfer.
|
|
||
| ## Beacon chain responsibilities | ||
|
|
||
| ### Proof re-signing |
There was a problem hiding this comment.
A validator that previously sent an invalid proof to some peers will be ignored by those peers for all future proofs. Re-signing by a different validator re-introduces the proof under a clean public key, preventing liveness issues where a subset of the network never sees a valid proof for a given block.
EIP-8025 specification refactor
This PR refactors the EIP-8025 specification across several dimensions: simplifying the proof engine interface, tightening gossip validation rules, improving sync protocol expressiveness, and replacing the prover relay model with a validator-driven proof re-signing flow.
Changes
beacon-chain.mdNewPayloadRequestHeadercontainer in favour of reusing the existingNewPayloadRequesttype already passed to the execution engine. We can introduceNewPayloadRequestHeaderwhen we actually use it in the BiB protocol.assert proof_engine.verify_new_payload_request_header(...)with a fire-and-forgetproof_engine.notify_new_payload(...)— the proof engine is informed of the new payload but consensus is not gated on its response.proof-engine.mdverify_new_payload_request_header→notify_new_payload, reflecting that this is a notification rather than a synchronous verification step.p2p-interface.mdexecution_prooftopic: deduplication byhash_tree_root(proof), and ignoring proofs from validators whose public key has previously produced an invalid proof.proof_typestoExecutionProofStatusas a dynamic capability advertisement, so peers can communicate which proof types they support without requiring a hard fork or new client release. This enables new proof types to be rolled out and adopted incrementally.proof_filters: List[ProofByRootIdentifier, ...]toExecutionProofsByRangeso callers can request specific proof types for specific block roots within a range, rather than fetching all proofs for all blocks. @nalepae had previously flagged this, and upon reflection, I think his proposal was correct.prover.mdBlockevents and proof engine completion events, tracks requests bynew_payload_request_root, and constructsSignedExecutionProofon completion.validator.md(new)SignedExecutionProofMAY re-sign and re-gossip it under their own key to ensure availability for peers that may have blacklisted the original signer due to a prior invalid proof submission.