Skip to main content

Indexer architecture

The Quantum explorer indexer is a search-first ingestion pipeline for Quantum chain data. It consumes Quantum-native RPC payloads and exposes a small health and metrics surface for operators.

Runtime shape

The indexer is intentionally single-process and sequential:

  1. Subscribe to eth_subscribe("newHeads") over WebSocket for low-latency head notifications.
  2. Fetch canonical blocks and receipts over HTTP JSON-RPC.
  3. Decode blocks as Quantum-native payloads, not generic Ethereum envelopes.
  4. Persist immutable chain facts.
  5. Advance the contiguous committed frontier only after the fact-store write has completed.

The WebSocket path is advisory. HTTP is the deterministic fetch path for initial catch-up, gap fill, and receipt hydration.

Data model

The indexer separates mutable runtime state from immutable chain facts.

Control plane — tracks the committed, finalized, and last-seen-head watermarks; per-block retry and cleanup state; metadata such as ABI records, verified contracts, and address labels. The committed-height value owns the visibility boundary for all explorer-facing reads.

Fact store — holds normalized, immutable chain facts:

  • blocks
  • txs
  • tx_calls
  • tx_signatures
  • receipts
  • logs
  • token_transfers

The explorer's hot reads (block lookup, address activity, log filters) hit the fact store; the committed-height clamp comes from the control plane.

Critical deviations from standard Ethereum

These are the things that will break a generic EVM indexer if you don't handle them.

1. Unknown transaction type 0x7A

Quantum uses a single custom EIP-2718 type 0x7A (QuantumTxEnvelope). There are no Legacy (0x00), EIP-2930 (0x01), EIP-1559 (0x02), EIP-4844 (0x03), or EIP-7702 (0x04) transactions.

Any indexer that whitelists known type IDs will reject every transaction.

2. The tx body is native AA — not a 1559 clone

Fields:

FieldTypeNotes
chain_idu64
senderAddressExplicit — ML-DSA is non-recoverable (no ecrecover)
nonce_keyU2562D nonce queue ID (0 = legacy sequential)
nonceu64Sequence within the queue
key_idu32References a KeyEntry in the on-chain KeyVault
max_priority_fee_per_gasu128
max_fee_per_gasu128
gas_limitu64
callsVec<Call>Batched calls, atomically executed
access_listAccessListEIP-2930 access list
fee_payerOption<Address>Gas sponsor (None = sender pays)
fee_payer_key_idOption<u32>
init_primary_pubkeyOption<Bytes>Bootstrap-only (first-use bootstrapKey())
init_cosigner_pubkeyOption<Bytes>Reserved; must be absent during bootstrap

Headline differences from EIP-1559:

  • Explicit sender — account identity is decoupled from signer-key derivation.
  • Batched calls instead of single to / value / input.
  • 2D nonces for parallel queues.
  • Gas sponsorship via optional fee_payer.
  • Explicit account bootstrap — first-use registration requires a dedicated bootstrapKey() call to KeyVault; init_primary_pubkey only appears on bootstrap txs.
  • Key-management lifecycleaddKey / removeKey / updateKeyAuth are explicit top-level lifecycle operations enforced by transient intent context; nested contract calls cannot trigger them.

3. Multi-scheme signatures, not ECDSA v / r / s

Transactions carry composite signatures — a mandatory primary plus an optional cosigner — instead of v / r / s. Four schemes:

SchemeTagPubkeySignatureWire total
ML-DSA-44 (FIPS 204)0x011,312 B2,420 B3,733 B
P256 (secp256r1)0x0264 B64 B129 B
ECDSA (secp256k1)0x0333 B64 B98 B
SLH-DSA 128s0x0432 B7,856 B7,889 B

Implications for an indexer:

  • No v / r / s fields exist. Each signature is a scheme_byte || pubkey || signature blob.
  • sender is an explicit field — it is the account lane, not derived from the signer's public key.
  • The fee payer signs over a different domain (0x78 prefix vs 0x7A) to prevent signature reuse.
  • Any code path that calls ecrecover or parses v / r / s will crash or return wrong addresses.

4. Block header has an extra field

The header wraps a standard Ethereum header and prepends one field:

RLP(QuantumHeader) = RLP([timestampMillisPart, ...standard 21 header fields...])
  • timestamp (seconds) — standard, EVM-compatible.
  • timestampMillisPart (u64, 0–999) — sub-second component for consensus ordering.
  • RPC responses include timestampMillis = timestamp * 1000 + timestampMillisPart.

Block hash = keccak256(rlp(QuantumHeader)). Any indexer that recomputes block hashes from the standard header fields alone will get mismatches.

5. No blob / EIP-7702 / beacon chain

FeatureStatus
Blob transactions (0x03)Not supported
EIP-7702 authorization listsNot supported
Beacon chain / slots / epochsNone — uses Simplex consensus
parent_beacon_block_rootNone or dummy
Uncles / ommersNone

Committed visibility boundary

The indexer never serves data that has not been fully committed. Concretely:

  • A new head from eth_subscribe("newHeads") triggers a fetch of the block and its receipts.
  • The block is decoded as a Quantum-native payload.
  • Fact rows are written to the fact store.
  • Only after the fact-store write completes does committed_height advance.
  • Read paths on the explorer clamp to committed_height.

This avoids race conditions where the explorer would show partial or torn data after a crash.