Repository navigation
feat(p2p): metrics for whether gossip validation competes with import - #752
MegaRedHand wants to merge 1 commit into
Conversation
Dedicated validation workers, bounded queues or CPU budgets are only
worth building if validation actually delays block import or epoch
precompute. Nothing measured that: the validation permit pools had no
metric, the existing arrival-to-verdict histogram cannot separate
blocking-pool queueing from run time, and the precompute histogram gives
a duration but no overlap with import latency.
Add, instrumentation only (no pool size, scheduling or verdict changes):
- lean_beacon_validation_permits_in_use{pool} and
lean_beacon_validation_permit_exhausted_total{pool}
- lean_beacon_validation_queue_seconds{kind} (spawn_blocking to closure
start) and lean_beacon_validation_run_seconds{kind}, for gossip stateful
checks and for the fetched column and envelope checks
- lean_beacon_column_check_permit_wait_seconds{kind}
- lean_beacon_epoch_precompute_running, 1 while a worker runs
Block import already exposes the mailbox wait as
lean_block_import_phase_seconds{phase="queue"}, so nothing is added there.
docs/metrics.md documents each metric and the PromQL for the question.
🤖 Codex Code ReviewLooks good overall: this PR is observability-only and does not change fork choice, attestation validation, justification/finalization, STF, XMSS, or SSZ logic. I did spot one correctness/readability issue worth fixing.
No security concerns stood out from this diff. Performance impact should be negligible: a few metric updates and Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
🤖 Claude Code ReviewI've reviewed the metrics changes and have no blocking issues. The commit is a single squashed import of the whole repo, so I couldn't diff against a base. I read the touched code directly: What looks good
Minor, non-blocking
Overall this is a clean, low-risk observability change. I'd approve it, with the small cleanups in Item 1 and Point 2 optional. Automated review by Claude (Anthropic) · sonnet · custom prompt |
🤖 Kimi Code ReviewI'll review this PR which adds metrics for validation contention and epoch precompute monitoring. Let me analyze each file carefully. crates/net/p2p/src/beacon/envelope_checks.rsBug: Incorrect pool label for envelope checks Line 113: This should be The Actually, re-reading: this is correct but fragile. The Line 113: The crates/net/p2p/src/beacon/verdict.rsLogic error in Lines 615-621: The Wait — let me re-check. Looking more carefully at However, line 615-616: Actually, looking at the original crates/net/p2p/src/metrics.rsPotential panic safety issue with Lines 526-533: More importantly: The Thread safety concern with Lines 482-503: The Histogram bucket allocation performance Lines 505-520: Actually, looking at the Missing Lines 524, 576, 600: PoolInUse::new("gossip"); // immediately dropped, then dec() called!This is a real bug risk. Add #[must_use]
pub(crate) struct PoolInUse(&'static str);Same for crates/blockchain/src/epoch_precompute.rsCorrectness: Gauge timing relative to actual work Line 224: However, the comment in crates/net/p2p/src/beacon/column_checks.rsCorrectness: Permit wait timing includes clone overhead Lines 49-52: let waiting_since = std::time::Instant::now();
let Ok(permit) = permits.clone().acquire_owned().await else {The crates/net/p2p/src/metrics.rs — Test issuesTest pollution risk Lines 838-874: Tests use But: Tests run concurrently and access global state. The The comment says "A pool label no real pool uses, so parallel tests cannot move it" — but parallel tests with the same test would collide. Rust runs tests in the same file concurrently by default. This is a test flake risk. Use Actually, re-reading: the tests are in Wait — the test creates Fix: Use a unique label per test invocation. Since there's no easy way to do this statically, use Simplest fix for use std::sync::atomic::{AtomicUsize, Ordering};
static TEST_COUNTER: AtomicUsize = AtomicUsize::new(0);
let test_id = format!("test_pool_{}", TEST_COUNTER.fetch_add(1, Ordering::SeqCst));
// ... use &test_idBut Alternatively, use a For Documentation
Lines 482-486: This is three separate expressions. In Grafana/promql, this would need to be separate panels or combined with Summary of Required Changes
The consensus-critical code (fork choice, attestation processing, etc.) is not modified in this PR — it's purely metrics instrumentation. The The guard-based RAII pattern for metrics is well-designed and panic-safe. The main risks are the Automated review by Kimi (Moonshot AI) · kimi-k2.6 · custom prompt |
…#752) Dedicated validation workers, bounded queues or CPU budgets are only worth building if validation actually delays block import or epoch precompute. Nothing measured that: the validation permit pools had no metric, the existing arrival-to-verdict histogram cannot separate blocking-pool queueing from run time, and the precompute histogram gives a duration but no overlap with import latency. Add, instrumentation only (no pool size, scheduling or verdict changes): - lean_beacon_validation_permits_in_use{pool} and lean_beacon_validation_permit_exhausted_total{pool} - lean_beacon_validation_queue_seconds{kind} (spawn_blocking to closure start) and lean_beacon_validation_run_seconds{kind}, for gossip stateful checks and for the fetched column and envelope checks - lean_beacon_column_check_permit_wait_seconds{kind} - lean_beacon_epoch_precompute_running, 1 while a worker runs Block import already exposes the mailbox wait as lean_block_import_phase_seconds{phase="queue"}, so nothing is added there. docs/metrics.md documents each metric and the PromQL for the question. Cherry-picked from perf/gossip-validation-contention-metrics at 5b4ed69.
) A range or by-root answer, or a batch of parked columns replayed after their parent imports, carries many columns of the same block. Each column was checked on its own blocking task with its own verify_cell_kzg_proof_batch call, and the chain actor heard nothing until every sidecar of the whole call was done, so data availability waited on the slowest block of the batch. check_and_forward now groups the sidecars by block (the signed header's root for fulu, beacon_block_root for gloas). A group takes one column_check_permits permit, runs every sidecar's rules that do not read the cells, then verifies the proofs of all sidecars still standing in one batch. A batch that fails is re-run sidecar by sidecar, so exactly the sidecars rejected before are rejected. The group's Keep and AwaitParent sidecars go to the chain actor as soon as the group finishes. Verdicts do not change: the proofs are the last rule on the chain path (the lookahead rule after them is the gossip path's alone), so chain_checks is now chain_precheck followed by a KZG step, with gossip's stateful_checks and stateful_checks_gloas keeping their order through the same split halves. On this machine a batch over 9-blob columns costs 3.3x less than separate calls at 8 columns and 4.8x less at 32. The branch's second commit verifies a block group's shared header signature once: every fulu sidecar of a block carries the same signed header, so the group repeated one BLS verification per sidecar, one after another under a single permit. SignatureMemo remembers header_signature_is_valid's answer for the group, keyed on the header root, the signature bytes and (for the head-state check made before parking) the head it read, so a forged signature over a shared header is judged on its own. Only that answer is remembered; every other rule runs per sidecar in its order, so verdicts are unchanged. The memo lives in one group's spawn_blocking closure; gossip and the single-sidecar wrappers use a fresh one per call. Adapted onto nightly's #752: its column_check in-use gauge and blocking-task timer now wrap one block group's closure instead of one sidecar's, and docs/metrics.md says a column_check permit and task cover a block's group. Cherry-picked from perf/column-kzg-batch-per-block at abe310a.
Block import benchmark (offline replay of mainnet blocks, steady state)
No measurable overhead on import. The replay has no gossip, so most of these metrics are not exercised there; the leg also served as a noise control. Method
|
🗒️ Description / Motivation
Dedicated validation workers, bounded queues or CPU budgets are only worth building if gossip validation actually delays block import or the epoch precompute. Nothing measured that: the validation permit pools had no metric, the existing arrival-to-verdict histogram cannot separate blocking-pool queueing from run time, and the precompute histogram gives a duration but no overlap with import latency.
Instrumentation only: no pool size, scheduling or verdict changes.
What Changed
crates/net/p2p/src/metrics.rs: new metricslean_beacon_validation_permits_in_use{pool}andlean_beacon_validation_permit_exhausted_total{pool}lean_beacon_validation_queue_seconds{kind}(spawn_blockingto closure start) andlean_beacon_validation_run_seconds{kind}, for gossip stateful checks and for the fetched column and envelope checkslean_beacon_column_check_permit_wait_seconds{kind}crates/blockchain/src/metrics.rs,epoch_precompute.rs:lean_beacon_epoch_precompute_running, 1 while a worker runsp2p/src/beacon/{verdict,column_checks,envelope_checks}.rs: observation sitesdocs/metrics.md: each metric, plus the PromQL that answers "does validation compete with import"Block import already exposes the mailbox wait as
lean_block_import_phase_seconds{phase="queue"}, so nothing is added there.Correctness / Behavior Guarantees
Tests Added / Run
cargo fmt --all -- --check: cleanmake lint: cleancargo test --profile release-fast -p ethlambda-p2p -p ethlambda-blockchain --lib --bins: p2p 364 passed (1 ignored), blockchain 292 passed (43 ignored)make test(spec suites); CI covers them.Related Issues / PRs
Part of a beacon import perf batch, each PR independent and based on
main. Overlap: this PR and the other batch PRs (STF phase timing, column KZG batching, engine/STF overlap) all editdocs/metrics.md; the column KZG batching PR also editsp2p/src/beacon/column_checks.rs.✅ Verification Checklist
make fmt— cleanmake lint(clippy with-D warnings) — cleanmake test(test-consensusplustest-node, atrelease-fast) — not run locally (spec suites); unit tests of the touched crates pass