You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On the multi-client devnet (8 aggregators across zeam / ethlambda / ream), zeam's per-aggregate build time is 5–7× higher than ethlambda's, measured cross-client at the same wall-clock with the same standard lean_pq_sig_aggregated_signatures_building_time_seconds histogram.
Aggregator
mean build time
sample count
head_slot
zeam_8
2.90 s
64
256
zeam_4
2.91 s
48
227
zeam_16
2.00 s
64
261
ethlambda_8
0.43 s
88
271
ethlambda_5
0.41 s
8
108
ethlambda_16
0.40 s
12
263
ream_0
(metric not exposed — see Notes)
—
223
ream_13
(metric not exposed)
—
215
(All numbers from each host's local Prometheus, snapshot 2026-05-19T15:13Z, ~30 min after fresh devnet restart.)
Verify side is fine across all clients (aggregated_signatures_verification_time is 35–71 ms; attestation_verification_time is 0.78–1.25 ms). The cost gap is squarely on the build path.
drops and queue saturation are clean on this run (lean_chain_queue_dropped_total = 0 for block and attestation queues on every zeam aggregator), so the slowness is not a queue-backpressure artifact and is not the regression PR #894 fixed. It's intrinsic per-aggregate cost.
Why it matters — direct FFG impact
Slow build → zeam aggregators frequently miss a slot's aggregation window (zeam_aggregate_skip_total{reason="in_flight"} ticks up because aggregate_group.concurrent is gated at concurrent_limit=1, see pkgs/node/src/chain.zig:4357). The downstream effect is visible directly in the next block proposal's coverage. From zeam_8 log at slot 256:
Subnets 0, 3, 5 are the three zeam-aggregator subnets. Subnet 5 contributed 1 of 8 votes. Subnet 0 contributed 3 of 8. Network coverage hovers around 70–72%, marginal vs the 67% justification threshold once any vote is on a divergent target — currently latest_justified_slot=0 and latest_finalized_slot=0 for every node in the devnet.
So this issue is the dominant single contributor to "no FFG progress" on the current cross-client devnet (other contributors — #863 slot-driver backlog, head divergence — are already tracked).
Snapshot under signatures_mutex — AggregateSnapshot.takeUnderLock. Comment claims O(10 ms) typical.
Compute with no lock held — agg.computeAggregatedSignatures(&state.validators, &snap.signatures, &snap.new_payloads, &snap.known_payloads). This is the heavy XMSS FFI path. The same docstring on aggregate() at line 2240 says "The ~18 s computeAggregatedSignatures runs in between with no locks" — i.e. the worst case acknowledged in code is ~18 s, and the live mean we measure today is 2–3 s.
So the work that's slow is phase 2 only — the FFI into multisig-glue for XMSS aggregation/proof-construction. Phases 1 and 3 are not the cost drivers.
ethlambda doing the equivalent work in 0.4 s is the strongest signal that this is not a fundamental cost of the spec — there is something specific to zeam's multisig FFI path that is 5–7× off.
Notes on cross-client comparability
lean_pq_sig_aggregated_signatures_building_time_seconds is part of the standard leanMetrics set, so the histogram name and semantics match across zeam / ethlambda by construction.
ream does not expose this histogram (or _total, _invalid_total, _in_aggregated_signatures_total, or the individual attestation_verification_time histogram). Their /metrics only carries _valid_total + _verification_time_seconds for aggregated sigs. That very likely means ream does not generate a recursive/SNARK aggregation proof at all (just packs verified XMSS sigs + a participation bitfield), and therefore has nothing to time. Worth confirming with the ream team before drawing conclusions, but it does suggest that even a SNARK-free packing is spec-acceptable.
Suggested investigation
Profile multisig-glue aggregation FFI under a representative load (8 raw atts, validator set 64) on a single host. Identify whether the cost is in:
per-signature recursive-proof witness construction (parallelisable per signature)
shared setup / SRS load (cacheable, currently re-done?)
bigint / hash-chain work (constant factor)
any debug-mode build artefact in the rust crate that landed on the devnet image.
Compare the multisig-glue API surface with what ethlambda uses. If they use a different (lighter) aggregation construction, decide whether to align — or document the cost/security trade-off.
Check parallelism.aggregate_io is concurrent_limit=1 (Off aggregate from libxev thread to avoid slot advance blocking #873), so two slots' aggregations cannot run in parallel, but within a single aggregation the per-signature work could be parallelised across a thread pool. Currently computeAggregatedSignatures appears to call FFI sequentially per attestation; verify and parallelise if so.
Verify Rust release-mode / opt-level on the devnet build. A 5–7× hit is consistent with debug-mode FFI, so rule that out first.
Add per-phase timing to aggregateUnlocked — break the histogram into phase1_snapshot, phase2_compute_ffi, phase3_commit so we can tell from Prometheus alone whether the cost is in the FFI or in surrounding Zig work.
Acceptance criteria
Mean lean_pq_sig_aggregated_signatures_building_time_seconds on a zeam aggregator ≤ 0.6 s on the multi-client devnet (matching ethlambda within ~1.5×).
On a 32-validator-per-subnet stress run, p99 build time ≤ 2 s.
zeam_aggregate_skip_total{reason="in_flight"} rate on a zeam aggregator drops by ≥ 4× compared to today's devnet baseline.
Per-phase build histogram exposed (phase1_snapshot, phase2_compute_ffi, phase3_commit) so we can attribute future regressions.
Block-proposal aggregate coverage from a zeam-managed subnet (0, 3, 5) reaches ≥ 6/8 in steady state on the same devnet.
Summary
On the multi-client devnet (8 aggregators across
zeam/ethlambda/ream), zeam's per-aggregate build time is 5–7× higher than ethlambda's, measured cross-client at the same wall-clock with the same standardlean_pq_sig_aggregated_signatures_building_time_secondshistogram.(All numbers from each host's local Prometheus, snapshot
2026-05-19T15:13Z, ~30 min after fresh devnet restart.)Verify side is fine across all clients (
aggregated_signatures_verification_timeis 35–71 ms;attestation_verification_timeis 0.78–1.25 ms). The cost gap is squarely on the build path.dropsand queue saturation are clean on this run (lean_chain_queue_dropped_total = 0forblockandattestationqueues on every zeam aggregator), so the slowness is not a queue-backpressure artifact and is not the regression PR #894 fixed. It's intrinsic per-aggregate cost.Why it matters — direct FFG impact
Slow build → zeam aggregators frequently miss a slot's aggregation window (
zeam_aggregate_skip_total{reason="in_flight"}ticks up becauseaggregate_group.concurrentis gated atconcurrent_limit=1, seepkgs/node/src/chain.zig:4357). The downstream effect is visible directly in the next block proposal's coverage. Fromzeam_8log at slot 256:Subnets 0, 3, 5 are the three zeam-aggregator subnets. Subnet 5 contributed 1 of 8 votes. Subnet 0 contributed 3 of 8. Network coverage hovers around 70–72%, marginal vs the 67% justification threshold once any vote is on a divergent target — currently
latest_justified_slot=0andlatest_finalized_slot=0for every node in the devnet.So this issue is the dominant single contributor to "no FFG progress" on the current cross-client devnet (other contributors — #863 slot-driver backlog, head divergence — are already tracked).
Where the cost lives
chain.zigsubmitAggregateOnInterval→aggregate_group.concurrenton the dedicatedaggregate_iothread (the move done in Off aggregate from libxev thread to avoid slot advance blocking #873).chain.zigaggregateImpl(pkgs/node/src/chain.zig:4371) →forkChoice.aggregate→aggregateUnlocked(pkgs/node/src/forkchoice.zig:2035).aggregateUnlockedis structured in three phases:signatures_mutex—AggregateSnapshot.takeUnderLock. Comment claimsO(10 ms)typical.agg.computeAggregatedSignatures(&state.validators, &snap.signatures, &snap.new_payloads, &snap.known_payloads). This is the heavy XMSS FFI path. The same docstring onaggregate()at line 2240 says "The ~18 scomputeAggregatedSignaturesruns in between with no locks" — i.e. the worst case acknowledged in code is ~18 s, and the live mean we measure today is 2–3 s.signatures_mutex— merge results, prune consumed snapshot vids. ms-scale.So the work that's slow is phase 2 only — the FFI into
multisig-gluefor XMSS aggregation/proof-construction. Phases 1 and 3 are not the cost drivers.ethlambda doing the equivalent work in 0.4 s is the strongest signal that this is not a fundamental cost of the spec — there is something specific to zeam's multisig FFI path that is 5–7× off.
Notes on cross-client comparability
lean_pq_sig_aggregated_signatures_building_time_secondsis part of the standard leanMetrics set, so the histogram name and semantics match across zeam / ethlambda by construction._total,_invalid_total,_in_aggregated_signatures_total, or the individualattestation_verification_timehistogram). Their/metricsonly carries_valid_total+_verification_time_secondsfor aggregated sigs. That very likely means ream does not generate a recursive/SNARK aggregation proof at all (just packs verified XMSS sigs + a participation bitfield), and therefore has nothing to time. Worth confirming with the ream team before drawing conclusions, but it does suggest that even a SNARK-free packing is spec-acceptable.Suggested investigation
multisig-glueaggregation FFI under a representative load (8 raw atts, validator set 64) on a single host. Identify whether the cost is in:aggregate_iois concurrent_limit=1 (Off aggregate from libxev thread to avoid slot advance blocking #873), so two slots' aggregations cannot run in parallel, but within a single aggregation the per-signature work could be parallelised across a thread pool. CurrentlycomputeAggregatedSignaturesappears to call FFI sequentially per attestation; verify and parallelise if so.aggregateUnlocked— break the histogram intophase1_snapshot,phase2_compute_ffi,phase3_commitso we can tell from Prometheus alone whether the cost is in the FFI or in surrounding Zig work.Acceptance criteria
lean_pq_sig_aggregated_signatures_building_time_secondson a zeam aggregator ≤ 0.6 s on the multi-client devnet (matching ethlambda within ~1.5×).zeam_aggregate_skip_total{reason="in_flight"}rate on a zeam aggregator drops by ≥ 4× compared to today's devnet baseline.phase1_snapshot,phase2_compute_ffi,phase3_commit) so we can attribute future regressions.aggregate coveragefrom a zeam-managed subnet (0, 3, 5) reaches ≥ 6/8 in steady state on the same devnet.Related
aggregate_iothread, the per-aggregate cost itself is 5–7× ethlambda.slot_interval/ tick duration (event-loop starvation vs nominal 0.8s) #863 — slowslot_interval/ libxev event-loop starvation. Slow aggregate build is one of the largest contributors to the kind of long FFI completions Investigate slowslot_interval/ tick duration (event-loop starvation vs nominal 0.8s) #863 is investigating, even now that build has been moved off the libxev thread.Devnet repro context
b2654679).geanandnleanslots replaced with zeam/ethlambda inlean-quickstartansible-devnet/genesis/validator-config.yaml).