Summary
On a mixed devnet where both clients verify the same gossiped aggregates, gean is consistently slower than ethlambda — +58% at p50, +32% on the mean, +57% at p99. The gap is across the whole distribution, not a tail artifact.
Aggregate verification runs per inbound gossip message, so this is hot-path work.
Measured
Local devnet, 8 gean + 6 ethlambda, 4 committees, ~2 h. Both clients on leanVM 48a90420. gean 14da17a, ethlambda 006453f4.
Both publish lean_pq_sig_aggregated_signatures_verification_time_seconds with identical bucket boundaries (0.1, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4) and comparable sample counts — ethlambda 3,339 per node, gean 2,897.
|
ethlambda |
gean |
gean slower |
| p50 |
0.0798 s |
0.1261 s |
+58% |
| p90 |
0.2096 s |
0.2324 s |
+11% |
| mean |
0.0959 s |
0.1265 s |
+32% |
| p99 |
0.2462 s |
0.3875 s |
+57% |
For context, the same run has the two clients matching to 3-4 significant figures on every other shared metric — attestation verify (4.951 ms vs 4.950 ms), attestation signing (0.531 s vs 0.526 s), state transition (0.2475 s vs 0.2475 s), gossip block size (248.5 KB both). Aggregate verification is the one place they diverge.
The measurement is clean
Checked before filing, because a same-named metric does not have to mean the same thing:
- One call site.
metrics.ObservePqSigAggVerificationTime is recorded only at internal/node/gossip.go:96, wrapping attestation.VerifyAggregatedGossipAttestation. Nothing in the aggregation path feeds the histogram, so gean is not mixing in child-proof verification from recursive aggregation.
- The shadow simulator is inert.
e.Shadow.SleepVerifyAggregated sits inside the timed region (gossip.go:95), but shadow-xmss-verify-aggregated-signatures-rate defaults to 0, shadow.sleep returns immediately at rate ≤ 0, and no shadow flag or env var is set on any node in the run.
- Same population. Both clients are timing verification of aggregates arriving over gossip, in a network where all four aggregators are gean, so both see the same stream of aggregates.
Why it matters
Verification is per inbound aggregate on the gossip path. At ~2,900 verifications per node over two hours, an extra ~46 ms at p50 is real CPU that competes with proving and with the engine loop. It is the same class of cost as #445 (block-proof verification delaying ticks), on a different path.
Not yet known
What ethlambda does differently. Candidates worth checking before optimising:
- whether the two spend their time in the same place (leanVM
verify vs the surrounding claim/signer-set reconstruction)
- whether gean rebuilds the signer set per verification where ethlambda caches or reuses
- whether
PubKeyCache is being hit on this path
- whether the difference is parallelism rather than per-call cost
A CPU profile of VerifyAggregatedGossipAttestation under devnet load would answer most of that. #443 asks for a reproducible proof benchmark; this path deserves one too.
Reproduce
Run a mixed devnet and compare the shared histogram:
histogram_quantile(0.50, sum by(job,le)(rate(lean_pq_sig_aggregated_signatures_verification_time_seconds_bucket[15m])))
Summary
On a mixed devnet where both clients verify the same gossiped aggregates, gean is consistently slower than ethlambda — +58% at p50, +32% on the mean, +57% at p99. The gap is across the whole distribution, not a tail artifact.
Aggregate verification runs per inbound gossip message, so this is hot-path work.
Measured
Local devnet, 8 gean + 6 ethlambda, 4 committees, ~2 h. Both clients on leanVM
48a90420. gean14da17a, ethlambda006453f4.Both publish
lean_pq_sig_aggregated_signatures_verification_time_secondswith identical bucket boundaries (0.1, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4) and comparable sample counts — ethlambda 3,339 per node, gean 2,897.For context, the same run has the two clients matching to 3-4 significant figures on every other shared metric — attestation verify (4.951 ms vs 4.950 ms), attestation signing (0.531 s vs 0.526 s), state transition (0.2475 s vs 0.2475 s), gossip block size (248.5 KB both). Aggregate verification is the one place they diverge.
The measurement is clean
Checked before filing, because a same-named metric does not have to mean the same thing:
metrics.ObservePqSigAggVerificationTimeis recorded only atinternal/node/gossip.go:96, wrappingattestation.VerifyAggregatedGossipAttestation. Nothing in the aggregation path feeds the histogram, so gean is not mixing in child-proof verification from recursive aggregation.e.Shadow.SleepVerifyAggregatedsits inside the timed region (gossip.go:95), butshadow-xmss-verify-aggregated-signatures-ratedefaults to 0,shadow.sleepreturns immediately at rate ≤ 0, and no shadow flag or env var is set on any node in the run.Why it matters
Verification is per inbound aggregate on the gossip path. At ~2,900 verifications per node over two hours, an extra ~46 ms at p50 is real CPU that competes with proving and with the engine loop. It is the same class of cost as #445 (block-proof verification delaying ticks), on a different path.
Not yet known
What ethlambda does differently. Candidates worth checking before optimising:
verifyvs the surrounding claim/signer-set reconstruction)PubKeyCacheis being hit on this pathA CPU profile of
VerifyAggregatedGossipAttestationunder devnet load would answer most of that. #443 asks for a reproducible proof benchmark; this path deserves one too.Reproduce
Run a mixed devnet and compare the shared histogram: