Skip to content

fix(node): warm KZG trusted setup at startup#24775

Open
spalladino wants to merge 2 commits into
merge-train/spartan-v5from
spl/a-1425-gossip-validation-taking-too-long
Open

fix(node): warm KZG trusted setup at startup#24775
spalladino wants to merge 2 commits into
merge-train/spartan-v5from
spl/a-1425-gossip-validation-taking-too-long

Conversation

@spalladino

Copy link
Copy Markdown
Contributor

Context

An RPC node logged Gossip validation for checkpoint_attestation took 15533ms, approaching mcache eviction window of 8400ms shortly after startup. Investigation (see A-1425) showed the validations were not slow — the Node.js event loop was fully blocked for 12–15s, and the attestations were queued behind it. The blocking call is getKzg(), which lazily builds the @crate-crypto/node-eth-kzg precomputation tables synchronously (~2s locally, 12–15s under the pod's CPU limits) on first use.

On a plain RPC node that first use is the archiver reconstructing blobs during sync, or the proposal handler uploading blobs right after a checkpoint arrives — both immediately adjacent to gossip traffic, so the stalled loop overruns the gossipsub mcache window (8.4s) and attestation forwarding is skipped. Sequencers already avoid this via Sequencer.init(), so only non-sequencer nodes were affected.

Approach

Warm the KZG singleton in createAztecNodeService, right after the existing bb.js WASM singleton init and before any subsystem runs. The cost is unchanged (every full node reconstructs blobs and pays it eventually) — it just moves off the gossip path to a point where blocking the loop is harmless. getKzg() is an idempotent per-process singleton, so this is a no-op for sequencers and for tests that pre-warm via warmBlobKzg (all e2e setups do), and adds no work for pure unit tests, which never construct a full node.

Fixes A-1425

The lazy KZG singleton (getKzg) builds its precomputation tables
synchronously on first use, blocking the event loop for ~2s locally and
12-15s under production CPU limits. On an RPC node the first use is the
archiver reconstructing blobs or the proposal handler uploading them,
right after a checkpoint arrives, so the stalled loop overruns the
gossipsub mcache window and attestation forwarding is skipped.

Warm it in the node factory alongside the bb.js singleton, before any
subsystem runs, keeping the cost off the gossip path.
Move the trusted-setup load timing and logging out of the node factory
and into getKzg itself, gated on an optional logger argument, using
elapsedSync for the measurement. Keeps the factory call site to a plain
getKzg(log) and makes the timing available to any warm-up caller.
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