Skip to content

The Indexer

Every AttestMesh node could follow the chain by polling eth_getLogs — and in fact every node does, permanently, as its fallback. The Indexer exists to make the live path fast and cheap: one service follows the chain once and pushes relevant events to subscribed members, instead of N nodes hammering RPC.

The design goal: gain that efficiency without creating a trusted middleman.

The Indexer is shared infrastructure: a single attested instance serves every cluster on the chains it watches. It discovers clusters automatically from the factory’s deployment events and filters per subscriber — members only ever receive events from their own cluster. Cluster bring-up ensures an indexer exists (no-op if one is registered); it never deploys one per cluster.

Like everything in AttestMesh, the Indexer is found on chain. The IndexerRegistry contract holds one operator-maintained record:

FieldMeaning
endpointThe gRPC URL members dial (through the dstack gateway).
codeIdThe indexer’s code identity (its CVM compose hash).
pubKeyThe Ed25519 key every push must verify against — derived inside the indexer’s TEE at boot.

Sidecars read current() at bring-up and re-read it whenever a subscription drops, so rotating the indexer is just an owner transaction.

Each pushed envelope carries:

  1. An Ed25519 signature over the canonical envelope content, verified against the registry pubkey. A push that fails verification tears down the subscription as adversarial.
  2. A TEE attestation quote binding that signing key to the indexer’s code identity (attached on the first push of each session).
  3. An RPC repro stub — the exact eth_getLogs call that reproduces the event from any RPC node, making every claim independently checkable.

And the sidecar adds a fourth layer by construction: verified pushes are wake-ups, not data. A push triggers the sidecar’s own chain reads (membership reconcile + log polling); the pushed payload is never written into state. The Indexer can therefore affect when a node learns something, never what it believes.

A member opens a bidirectional gRPC stream and sends a Hello naming its cluster and member id (verified against chain state) plus a resume cursor. The indexer replays everything since the cursor, then streams live, advancing a persistent per-member cursor on acks — so a node that was offline replays exactly what it missed.

The Indexer is liveness-only by design:

  • Down? Sidecars log the failed subscription, keep polling chain logs (their poll interval is the worst-case latency), and resubscribe with backoff.
  • Wrong or omitted events? Signature verification kills bad pushes; the always-on polling path converges regardless of omissions.
  • Replaced? The owner updates the registry; subscribers re-discover and re-verify against the new key.

A cluster never needs the Indexer to be correct — only to be fast.