An RPC provider needs to know which blocks a node can answer for, and what it says when it cannot. An xOneRS full node answers state reads inside a recent window and refuses older ones with a typed -32000 unsupported history error that names the first retained block. An archive node answers state reads at any canonical block. eth_capabilities tells a client the oldest block the node serves for each kind of data. On Apothem, the committed RPC parity report compares 19 blocks per method against geth-XDC with 0 differences.
For the method list, see the xOne RPC surface; for safe exposure, see exposing xOne JSON-RPC safely.
Archive or full: which does a provider need?
| Need | Full node | Archive node |
|---|---|---|
eth_getBalance, eth_getCode, eth_getStorageAt, eth_getTransactionCount, eth_call at an old block |
refused below the window | answered at any canonical block |
| Blocks, transactions, receipts, logs | inside the retained history | inside the retained history |
eth_getProof |
inside the state window since PR #1097; below it, unsupported history |
served since PR #1097; proofs at old blocks of an archive node were not checked |
Two settings on main change the retained history (PR #1100, PR #1135, 2026-11-15): --history.bodies, --history.receipts and --history.logs keep only that many recent blocks (0 keeps the whole chain), and a request below the floor gets the typed unsupported history error; --history.bodies-from and --history.receipts-from make a snap-synced node fetch bodies and receipts below its snapshot floor in the background, each batch checked against the stored headers. Neither is in v0.1.0.
An archive node is started with --gcmode archive --syncmode full on an empty datadir; it cannot start from a snap pivot (archive mode, docs/ops/archive.md).
What does a node answer below its window?
A typed error, never an empty or zero answer:
{"code": -32000, "message": "unsupported history: ...",
"data": {"class": "...", "block": ..., "firstRetained": ..., "pivot": ...}}
data names the kind of data, the block asked for, the first retained block and the snap pivot (types.rs). A failed store read is also a server error, never a default value. A provider can route the request to an archive node on this code instead of returning a wrong zero.
How can a client ask what the node serves?
eth_capabilities returns the head (number and hash) and, for state, tx, logs, receipts and blocks, the oldestBlock the node serves. stateproofs is disabled, because eth_getProof is not served. The numbers come from the same retention that refuses a read below it, so the two never disagree (eth.rs, PR #883). eth_config returns the fork configuration (EIP-7910).
How was parity checked on Apothem?
The committed Apothem report replays recorded geth-XDC answers against xOneRS up to block 1,800 (apothem.json):
- 60 methods, 2,610 rows: 820 equal, 0 differ, 1,774 not backed, 16 allowlisted.
- For most block-keyed methods, 19 blocks are compared, for example
XDPoS_getMasternodesByNumber,eth_getBlockFinalityByNumber,eth_getLogsanddebug_getRawBlock, each 19 of 19 equal. - Rows for blocks above 1,800 are not backed: the harness has no executed block, receipts or state there.
The numbers for both networks are in RPC parity in numbers. The scope tracker for the RPC work, issue #42, is closed.
How do other clients describe history limits?
| Client | What its documentation states | xOne |
|---|---|---|
| ethrex | A snap-synced node keeps headers only below the pivot, so pre-pivot history reads return empty; backfill is opt-in, as stated in ethrex sync modes | below the window, a typed unsupported history error, never empty |
| reth | Pruned segments change which RPC calls a node can answer; the pruning page has availability tables, as stated in reth pruning | eth_capabilities reports the oldest served block per kind of data |
Frequently asked questions
What does unsupported history mean on xOne?
The node does not hold that data for the block you asked about. The error is -32000, and data.firstRetained is the oldest block it holds for that kind of data.
Which xOne node type answers eth_call at an old block?
An archive node, started with --gcmode archive --syncmode full on an empty datadir.
How can my load balancer route by history?
Read eth_capabilities once per node to learn oldestBlock per kind of data, and route on the unsupported history error code.
Is eth_getProof served?
No. eth_capabilities reports stateproofs as disabled.
Sources
This article describes the source and evidence at its review date. Check the linked repository for current implementation and qualification status.
Explore the engineering evidenceEdit this page on GitHub opens the Markdown source (content/blog/apothem-rpc-providers/index.md). GitHub may ask you to sign in. Report a correction opens a prefilled GitHub issue for this page.