Skip to content

Add execution proof network test crate (optional-proofs-gloas-pr-5) - #44

Open
frisitano wants to merge 4 commits into
optional-proofs-gloasfrom
optional-proofs-gloas-pr-5
Open

Add execution proof network test crate (optional-proofs-gloas-pr-5)#44
frisitano wants to merge 4 commits into
optional-proofs-gloasfrom
optional-proofs-gloas-pr-5

Conversation

@frisitano

@frisitano frisitano commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds testing/execution_proof_network_tests, a reusable deterministic harness for multi-node EIP-8025 execution-proof integration tests, built on the simulator's LocalNetwork rather than a second node orchestrator.

  • Topology: NodeSpec chooses per node whether it runs a proof engine, which proof bytes that engine accepts, and whether it carries validators. ProofNetworkConfig sets validator count, slot duration, genesis delay and the Gloas fork epoch.
  • Proof-engine injection: each node gets its own MockProofEngine through a new ClientConfig::proof_engine_override field, gated behind a test-utils feature on the client crate and never serialized, so valid and invalid proof data are chosen per scenario without an ere-verifier build. Production builds of lighthouse do not enable the feature, and Config::proof_engine_override() returns None there.
  • Submission: signed_execution_proof builds and signs envelopes with the deterministic interop validator keys. submit_execution_proof runs the same verify, cache, publish sequence the pending Beacon API endpoint will expose; publish_execution_proof injects an unverified proof onto gossip, as a faulty peer would.
  • Observation: ProofStatus snapshots, per node, whether the block is known, a valid proof of a type was verified, which proof types the pending payload cache holds, whether the envelope is stored, and whether fork choice has the payload. Waits are bounded and print every node's status and peer count on timeout.
  • Scenarios: Gloas baseline (verifiers hold payloads until two proofs), end-to-end submit → propagate → verify → cache → payload import, invalid proof data rejected by a verifier that does not accept it (with peer penalty and an honest-prover control), and unsupported proof type rejected before verification.

Production changes are small and additive: the simulator gains a library target (main.rs now uses it), Client exposes network_senders() and network_globals(), PendingPayloadCache gains cached_execution_proof_types(), ProofEngine implements Debug so it can live in ClientConfig, and the override field itself only exists with client/test-utils.

Known blocker on this base

GossipVerifiedExecutionProof::new loads the payload envelope with store.get_payload_envelope, but a node with a proof engine persists the envelope only in import_execution_payload_envelope, after required_execution_proofs (2) are cached. So every proof reaching a proof-engine node fails with PayloadUnavailable, and the two scenarios that depend on proof verification cannot pass yet. A fallback to pending_payload_cache.get_executed_payload_envelope would resolve it; per conductor-nova that finding is routed to the EL-optional task (#42) rather than fixed here.

Pending integration points (documented in the crate docs, not reimplemented)

Validation

Base: 535046063ae2152e351164843e2488b5bdc64746 (origin/optional-proofs-gloas).

Check Result
cargo fmt --all -- --check pass
cargo clippy with the Makefile lint flags: client and beacon_node without test-utils, the test crate and client with it pass
gloas_network_imports_payload_envelopes (release) pass, 42s
unsupported_proof_type_is_rejected_before_verification (release) pass, 37s
execution_proofs_propagate_verify_and_unlock_payload_import ignored: fails at submission with PayloadUnavailable (blocker above)
invalid_proof_data_is_rejected_by_verifiers_that_do_not_accept_it ignored: same PayloadUnavailable failure

Run the two ignored scenarios with --run-ignored all once the envelope lookup is fixed; they carry the full assertions and no other change is needed.

Run the suite with make test-execution-proof-network (cargo nextest run -p execution_proof_network_tests --release --test-threads 1). Tests bind the simulator's fixed ports, so they are serialised in-process and ignored in debug builds.

Reviewer focus

  1. beacon_node/client/src/config.rs: the test-utils-gated proof_engine_override field and its accessor; feature unification enables it for any build that includes the test crate.
  2. testing/execution_proof_network_tests/src/prover.rs: the submission adapter mirrors the future Beacon API handler; confirm the sequence matches the intended endpoint.
  3. testing/execution_proof_network_tests/src/tests.rs: topology and assertions for the four scenarios.

Move the module tree into `lib.rs` so other testing crates can reuse
`LocalNetwork`, the checks and the retry helper instead of duplicating
node orchestration. The `simulator` binary keeps its subcommands and now
builds on the library.
Let tests drive a production beacon node's proof pipeline without an
`ere-verifier` build or a Beacon API:

- `ClientConfig::proof_engine_override` injects a ready-built
  `ProofEngine` (never serialized) ahead of the `proof_engine` config, so
  each node can run its own mock verifier.
- `Client::network_senders()` and `Client::network_globals()` expose the
  network channels and peer state for publishing proofs and reading peer
  scores.
- `PendingPayloadCache::cached_execution_proof_types()` reports which
  proof types are cached for a block.
- `ProofEngine` implements `Debug` so it can live in `ClientConfig`.
Add `testing/execution_proof_network_tests`, a deterministic multi-node
harness for EIP-8025 execution proofs built on the simulator's
`LocalNetwork`. Tests choose per node whether it runs a mock proof
engine, which proof bytes it accepts and whether it carries validators;
sign proof envelopes with the interop validator keys; submit them through
a node (verify, cache, publish) or inject them unverified onto gossip;
and observe verification, caching, storage and payload import on every
node with bounded waits that print a per-node snapshot on timeout.

Four scenarios cover the Gloas baseline (verifiers hold a payload until
two proof types arrive), the end-to-end submit, propagate, verify and
import path, invalid proof data rejected by a verifier that does not
accept it, and an unsupported proof type rejected before verification.
The two scenarios that need proof verification are ignored on this base:
gossip verification loads the envelope from the store, which a
proof-engine node fills only after two proofs, so submission fails with
`PayloadUnavailable`. They carry the full assertions for when that is
fixed.

Tests bind the simulator's fixed ports, so `make
test-execution-proof-network` runs them sequentially in release and the
workspace test targets exclude the crate.
Keep `ClientConfig::proof_engine_override` out of production builds: the
field, its default and the builder branch now exist only with the new
`client/test-utils` feature, and `Config::proof_engine_override()`
returns `None` without it. The execution proof network test crate
enables the feature, and feature unification makes the field available
to `beacon_node` and `node_test_rig` in that build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant