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.
One instance, every cluster
Section titled “One instance, every cluster”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.
Discovery through the chain
Section titled “Discovery through the chain”Like everything in AttestMesh, the Indexer is found on chain. The IndexerRegistry contract holds one operator-maintained record:
| Field | Meaning |
|---|---|
endpoint | The gRPC URL members dial (through the dstack gateway). |
codeId | The indexer’s code identity (its CVM compose hash). |
pubKey | The 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.
Three layers of verifiability
Section titled “Three layers of verifiability”Each pushed envelope carries:
- An Ed25519 signature over the canonical envelope content, verified against the registry pubkey. A push that fails verification tears down the subscription as adversarial.
- A TEE attestation quote binding that signing key to the indexer’s code identity (attached on the first push of each session).
- An RPC repro stub — the exact
eth_getLogscall 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.
Subscription model
Section titled “Subscription model”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.
Failure behavior
Section titled “Failure behavior”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.