Summary
Add differential ("parity") tests that compare the indexer's answers against the legacy archive-node-api on devnet, to (a) catch indexer correctness regressions against a known-good oracle and (b) build the evidence that the indexer can replace the archive-node-api for downstream consumers (notably o1js fetchEvents / fetchActions).
Two production surfaces (probed 2026-06-18):
- Indexer:
https://devnet-indexer.gcp.o1test.net (REST /summary + GraphQL /graphql)
- Archive node API:
https://devnet-archive-node-api.gcp.o1test.net (GraphQL only)
Comparable surface (what overlaps)
The archive-node-api is narrow — its entire query surface is blocks, events, actions, networkState. The indexer is a superset (block(s), events, actions, accounts, transaction(s), internalCommands, snarks, stakes, tokens, …). So the parity scope is exactly the overlap:
| Target |
indexer |
archive-node-api |
Priority |
| zkApp events per account |
events |
events |
★ highest — the archive-node-api's whole purpose; backs o1js fetchEvents |
| zkApp actions per account |
actions |
actions |
★ highest — backs o1js fetchActions |
| block by height / state-hash (+ its commands) |
block/blocks |
blocks |
high |
| tip / network state |
/summary (loosely) |
networkState |
liveness sanity only |
Note: the indexer's /summary has no real archive-node-api counterpart beyond a loose networkState match — it is not a good comparison target. Don't anchor the tests on /summary vs archive.
Test design
Property (differential equivalence) over random valid inputs:
∀ height h in [genesis+1, min(tip_indexer, tip_archive) − MARGIN],
∀ account a in {discovered zkApp accounts}:
normalize(indexer.query(a, h)) == normalize(archive.query(a, h))
- Generators: random finalized
h; random a from a discovered set of zkApp accounts active on devnet.
- Use
proptest for the in-repo (hermetic) version — shrinking yields the minimal failing (h, a). Seeded RNG for the live monitor.
The flake-prone parts to handle explicitly:
- Tip skew / reorgs — both follow the tip independently and will disagree at the head. Only compare at
min(tip) − MARGIN with MARGIN ≥ k (290) (finalized). This single rule removes ~all false positives.
- Schema normalization — different schemas: map field names, sort events/actions deterministically (order not guaranteed equal), normalize units (nanomina vs decimal), null-vs-empty, pagination. Project both into one canonical struct, compare that.
- Canonical-only — filter both to the canonical chain (the indexer also serves non-canonical blocks).
- Gentle on prod — read-only, low concurrency, bounded request budget. This is a correctness probe, not a load test.
Placement — split into two halves (they have opposite requirements)
A. Hermetic golden parity → this repo (fold into #19)
Ingest a fixed devnet block range, capture archive-node-api responses for that range once as golden fixtures, assert the indexer reproduces them. Deterministic, offline, no live dependency → safe to gate every PR. Belongs here because it tests this code in this CI. Reuses the e2e harness proposed in #19.
B. Live randomized differential vs prod → integration/monitoring repo, scheduled
Comparing two live deployments is tip-sensitive and depends on both services being up — a cross-service acceptance/monitoring concern, not per-PR CI (external flakiness must not gate indexer PRs). Home: a neutral mina-indexer-parity repo (or an org integration-tests repo) running a cron against devnet prod, alerting on divergence. This is the right place for the "minaprotocol/integration-tests"-style live check.
Deliverables
Out of scope
Notes
- Highest ROI is events/actions parity: it's the archive-node-api's reason to exist and the concrete blocker to pointing o1js at the indexer.
- Probed surfaces confirm the overlap above; archive-node-api root fields =
{events, actions, networkState, blocks}.
Related: #19 (testing investment plan — the hermetic half lives there).
Summary
Add differential ("parity") tests that compare the indexer's answers against the legacy archive-node-api on devnet, to (a) catch indexer correctness regressions against a known-good oracle and (b) build the evidence that the indexer can replace the archive-node-api for downstream consumers (notably o1js
fetchEvents/fetchActions).Two production surfaces (probed 2026-06-18):
https://devnet-indexer.gcp.o1test.net(REST/summary+ GraphQL/graphql)https://devnet-archive-node-api.gcp.o1test.net(GraphQL only)Comparable surface (what overlaps)
The archive-node-api is narrow — its entire query surface is
blocks,events,actions,networkState. The indexer is a superset (block(s),events,actions,accounts,transaction(s),internalCommands,snarks,stakes,tokens, …). So the parity scope is exactly the overlap:eventseventsfetchEventsactionsactionsfetchActionsblock/blocksblocks/summary(loosely)networkStateTest design
Property (differential equivalence) over random valid inputs:
h; randomafrom a discovered set of zkApp accounts active on devnet.proptestfor the in-repo (hermetic) version — shrinking yields the minimal failing(h, a). Seeded RNG for the live monitor.The flake-prone parts to handle explicitly:
min(tip) − MARGINwithMARGIN ≥ k (290)(finalized). This single rule removes ~all false positives.Placement — split into two halves (they have opposite requirements)
A. Hermetic golden parity → this repo (fold into #19)
Ingest a fixed devnet block range, capture archive-node-api responses for that range once as golden fixtures, assert the indexer reproduces them. Deterministic, offline, no live dependency → safe to gate every PR. Belongs here because it tests this code in this CI. Reuses the e2e harness proposed in #19.
B. Live randomized differential vs prod → integration/monitoring repo, scheduled
Comparing two live deployments is tip-sensitive and depends on both services being up — a cross-service acceptance/monitoring concern, not per-PR CI (external flakiness must not gate indexer PRs). Home: a neutral
mina-indexer-parityrepo (or an org integration-tests repo) running a cron against devnet prod, alerting on divergence. This is the right place for the "minaprotocol/integration-tests"-style live check.Deliverables
events/actions/blocks.proptest-based hermetic parity tests inmina-indexer, driven by recorded golden archive responses over a fixed devnet range (under Testing investment plan: coverage, PCB-driven e2e correctness, feature & security tests #19's harness).mina-indexer-parityrepo vs existing integration-tests).Out of scope
Notes
{events, actions, networkState, blocks}.Related: #19 (testing investment plan — the hermetic half lives there).