A blockchain dataset can pass every structural check and still be missing rows that nothing inside it points to. SQD reconciles its data against independent sources on the way in and serves the full history, genesis to head, across 225+ networks from one API. A query pinned to a block range returns the same rows on every run, so a reviewer can re-derive any figure.
A research dataset gets checked twice, once by the team that built it and once by whoever reviews the numbers it produced. Structural checks pass when block numbers are contiguous and keys are unique, and Merkle proofs pass when the rows you hold hash into the block header, but both only describe the records that are present. A record that was never written leaves no trace in either. The check that catches it is not a proof but a reconciliation against an independent source, which SQD runs against its own data on the way in.
The failure is concrete, not hypothetical. Polygon's state-sync transactions, the mechanism that delivers bridged deposits from Ethereum, were excluded from the block's transactionsRoot, receiptsRoot, and logsBloom until the December 2025 hard fork that activated PIP-74, which is most of the chain's history. A pipeline that prefilters blocks by the header bloom drops their logs; a check against receiptsRoot accepts the resulting gap. Queried live over a 30,000-block window, the class is not small:
The check that catches a missing record of this class is not a proof but a reconciliation: counting against an independent source at escalating granularity, down to the record. The validation guide runs that procedure end to end on this exact window and lands on real missing rows in a second source; the proofs guide covers the mechanism. SQD runs the same reconciliation against its own data on the way in.
The pull itself is one pinned request, here narrowed to a single sprint-boundary block:
It returns two StateCommitted logs. The first, verbatim:
Both rows sit on transactionIndex 114 of block 74,614,768: a synthetic transaction, 0x167f…3ec7, appended after the block's 114 canonical ones, with no signer and no gas. That placement is the gotcha: a pipeline keyed to the canonical transaction list never reaches index 114, and whether an archive node's eth_getLogs returns these logs depends on the client, while the receipt call does return them. Portal serves them as ordinary rows.
Historical depth is not a separate tier or an archive product: every dataset runs from block 0. On Ethereum, the first transaction ever mined sits in block 46,147, and the request for it is the same shape as a request at head:
That is 31,337 wei sent by 0xa1e4…63b4 on 2015-08-07, transaction 0x5c50…2060. Two mechanics to note before building on the stream: value arrives as hex wei ("0x7a69"), so convert before aggregating, and the stream returns only blocks with matching data plus sparse chunk-boundary headers, so counting response lines does not count scanned blocks.
Pulling the same history over RPC means archive access for old ranges and per-provider eth_getLogs caps that differ by an order of magnitude between endpoints, measured in the eth_getLogs guide. Here a full-history extraction is one streamed range request, and because the range above is pinned below the finalized head, re-running it returns the same rows: the request body committed next to a result is the result's audit trail.
Every block, transaction, log, trace, and state diff from block 0 through the chain head, served by the same query shape as live data. A full-history backfill is one streamed range request per dataset, not a pagination loop against per-call caps.
Structural checks and Merkle proofs verify the rows you have; neither catches a record that was never written. SQD reconciles record counts against independent sources on the way in, the only check that catches records a block header never committed to.
A query pinned to a fixed block range is deterministic: the same request returns the same rows on every run. Commit the request body next to the figures it produced and a reviewer re-derives the dataset instead of trusting an export.
Stream NDJSON over plain HTTP, or load ClickHouse, Postgres, MongoDB, SQLite, or Parquet on S3 with the Squid and Pipes SDKs, plus a custom-target API for any warehouse. The rows land in infrastructure you run, and what you compute on them stays internal.
Every record here is public onchain; the difference is whether the set can be shown complete and whether a figure can be re-derived.
See this on your own contracts
Tell us the chains and contracts you care about, and we will show you the query that returns them.
Cryptographic proofs verify the onchain data you have, not whether it is complete. Why proof-based validation misses whole classes of logs, shown with Polygon state-sync, and how to query the full set.
Structural checks prove a dataset is well-formed, not complete. The reconciliation method that finds missing rows: count against an independent source, escalate granularity from days to the record. Worked live with Portal and Dune.
eth_getLogs is the standard way to read events, and the first wall teams hit. The block-range and result caps that force pagination, the archive requirement, and a real block where eth_getLogs omits logs the receipt returns.
Transfers, mint and burn, and peg signals read from DEX trades.
Issuance, transfers, and the issuer control events a token API omits.
Pool discovery from factory events, and every trade the pools emit.
Item ownership, game currencies, and marketplace settlement onchain.
Registrations, delegation, and the social graph that stays onchain.
Private Portal. Dedicated. Validated. Managed. Tell us what you're building, we'll show you what it looks like on SQD.