Indexing & Verification
How an indexer discovers, orders and validates Sigil records.
ProposedAn indexer turns chain history into Saelis state. It is where the protocol's rules are actually executed, so its design determines whether two parties can independently arrive at the same answer.
Pipeline
A conforming indexer is a deterministic pipeline:
| Stage | Input | Output |
|---|---|---|
| Source | Elysium RPC | Blocks with full transactions and receipts |
| Extract | Transactions | Candidate payloads, according to the transport |
| Decode | Payloads | Parsed envelopes, or rejection reasons |
| Order | Envelopes | Envelopes in canonical order |
| Validate | Ordered envelopes | Outcomes under the envelope and standard rules |
| Apply | Valid operations | Sigils, references, assemblies and standard state |
| Serve | State | An API for applications |
Every stage except Source and Serve must be a pure function of its input. Given the same blocks, the output must be identical.
Scanning blocks
The following processes a block range with viem. It is real, runnable code for the Source and Extract stages under the calldata candidate transport.
import type { Block, Transaction } from 'viem'
import { publicClient } from './lib/client'
import { parseSigil } from './parse-sigil'
export async function scanRange(from: bigint, to: bigint) {
const candidates = []
for (let number = from; number <= to; number++) {
const block = await publicClient.getBlock({ blockNumber: number, includeTransactions: true })
for (const tx of block.transactions as Transaction[]) {
const envelope = parseSigil(tx.input)
if (!envelope) continue
const receipt = await publicClient.getTransactionReceipt({ hash: tx.hash })
if (receipt.status !== 'success') continue
candidates.push({
id: tx.hash,
creator: tx.from,
block: block.number,
index: receipt.transactionIndex,
envelope,
})
}
}
return candidates
}At 100 ms per block, Elysium produces about 864,000 blocks per day. Production indexers should request blocks concurrently in bounded batches, use a dedicated archive endpoint and persist progress so that scanning can resume.
Canonical ordering
Candidates are sorted by (block, index) and, if multiple Sigils per transaction are permitted, by their intra-transaction index. Validation then proceeds strictly in that order, because the validity of an operation can depend on every operation before it.
Validation
Validation is the Saelis-specific core and the least settled part of the design. The shape is fixed, even though the rules are not:
Draft Example — Not Finalized
// Pseudocode. The rules referenced here are drafts.
for (const candidate of sortByPosition(candidates)) {
const envelopeResult = validateEnvelope(candidate.envelope)
if (!envelopeResult.ok) {
record(candidate, envelopeResult.reason)
continue
}
const standard = standards.get(candidate.envelope.std ?? '')
if (!standard) {
record(candidate, 'valid:uninterpreted')
continue
}
const outcome = standard.apply(state, candidate)
record(candidate, outcome)
}Finality
Elysium's sequencer confirms transactions quickly, while settlement to HyperEVM happens later. Before a block is final it can, in principle, be reorganized.
The Elysium testnet RPC supports the standard safe and finalized block tags, which lag behind latest:
import { publicClient } from './lib/client'
const [latest, finalized] = await Promise.all([
publicClient.getBlock({ blockTag: 'latest' }),
publicClient.getBlock({ blockTag: 'finalized' }),
])
console.log(latest.number - finalized.number) // blocks not yet finalAn indexer can either process only finalized blocks, accepting a delay, or process latest blocks and roll back state when a reorganization is detected by a change in a previously seen block hash. Many indexers do both, exposing a provisional and a final view.
Verification
Indexer output is derived data. Users and applications should be able to verify it:
- Spot checks. Any Sigil returned by an indexer can be checked by fetching its transaction directly and re-parsing it, as shown in Reading Sigils.
- State commitments. An indexer can publish a hash of its state at a block height. Two indexers that agree on the hash agree on the entire state.
- Test vectors. Conformance is demonstrated by reproducing the published test vectors for each standard exactly.