Three XDC clients, side by side
Live RPC, snapshot-size and consensus-parity results across three independent XDC clients: the legacy XDPoSChain client (rpc.xinfin.network · v2.6.8, a 2018 Geth ~1.8.3 fork), the modern re-baseline (new.xdcrpc.com · Geth v1.17.3-stable), and the Erigon client (02.xdcrpc.com/erigonrpc · Erigon 3.x). Calls run from your browser, latency is measured per-method, parity is checked against expected values. Verified bit-exact, in-sync at block #103.4M (2026-06-03).
Point the test runner at three RPC nodes
Defaults below run against XDC mainnet public RPC for the legacy client, the modern v1.17.3 re-baseline (branch reset/integration-1.17.3) and the 02.xdcrpc.com/erigonrpc Erigon node. Swap any of them for an internal or test endpoint. Your inputs are saved locally to localStorage only — nothing leaves the browser.
https://rpc.xinfin.network
https://new.xdcrpc.com/
https://02.xdcrpc.com/erigonrpc
About these calls
Each method is invoked over HTTPS POST as a JSON-RPC 2.0 request directly from your browser. Latency is wall-clock time measured with performance.now(). Parity status is computed against a known-good expected value (chain ID, base fee) or by cross-comparing the endpoints against the modern node (genesis hash, block hash, state root, balance). The legacy and modern defaults (rpc.xinfin.network, new.xdcrpc.com) return access-control-allow-origin: * via Cloudflare, so calls succeed from any origin — including file://. If a column reports a network error on every row, the most likely cause is missing CORS headers on that endpoint — enable them at the edge (Cloudflare response-header rule adding access-control-allow-origin: *) or on the node itself (--http.corsdomain "*", and for Erigon --rpc.accessList / a CORS-enabled reverse proxy).
⚡ Erigon CORS error? Fix it in 60 seconds ›
If every Erigon row shows a network error, the endpoint at 02.xdcrpc.com/erigonrpc is missing Access-Control-Allow-Origin headers. Two fixes — choose the one that matches your setup:
Set: Access-Control-Allow-Origin → *
(Cloudflare Dashboard → Rules → Transform Rules → Response Headers)
--http.corsdomain "*"
Side-by-side, measured in real time
Identical request payloads against all three endpoints, cross-checked against the modern node. Status column: PASS matches expected, FAIL diverges, DIFF intentional (e.g. client version), N/A unsupported on that client.
Legacy · ~Geth 1.8.3
Modern · Geth v1.17.3
Erigon · 3.x
Where the bytes live — legacy hash scheme vs PBSS
Measured on XDC mainnet production nodes synced to head (~block 103.3M, syncing=false, 24 peers, May 2026). Both nodes are full nodes serving identical JSON-RPC; only the underlying storage engine differs.
Legacy XDPoSChain v2.6.8 hash scheme · LevelDB
Growth rate ~14 GB / week. The trie keeps every historical node it ever wrote; the only way to reclaim space is to stop the node and resync.
Modern Geth v1.17.3 fork PBSS · Pebble
Live-state portion stays flat at ~22 GB. No resync ritual. Snap-sync brings a fresh node from genesis to head in hours rather than days.
| Disk subsystem | Legacy (1.8.3) | Modern (1.17.3) | Δ | Mechanism |
|---|---|---|---|---|
| Full-node total | 919 GB | 303 GB | −3.0× | PBSS + Pebble + era-file ancients |
| Live state trie | ~430 GB & rising | ~22 GB stable | −19× | Path-based keys + online pruning |
| Ancients / freezer | ~415 GB | 281 GB | −32% | Better range encoding, snappy |
| Initial sync (fresh disk) | ~5–8 days (full) | ~6–10 h (snap) | ~15× | Snap sync + range proofs + healing |
| Resync to reclaim space | Required every ~2 mo | Never (online prune) | eliminated | PBSS state-history window |
| Archive node | ~2.5 TB · slow reads | ~1.6 TB · O(1) reads | −36% + faster | PBSS archive + flat snapshot |
| Cold-cache RPC read (eth_getBalance) | ~40–120 ms | ~3–8 ms | ~10–15× | Snapshot flat-layer lookup |
| Memory footprint (steady state) | ~8–16 GB | ~3–6 GB | −2× to −3× | Pebble cache + bounded PBSS |
Snapshot taken on a single production node; absolute numbers vary with peer churn, indexing config and freezer cutoff. Ratios are the engineering-stable claim.
What each test should return, and why
For every JSON-RPC method below the comparison is well-defined. Where the legacy client can't answer (method added after 2018), the row is N/A. Where the response is supposed to differ between clients (e.g. client version string), the row is DIFF. Everything else must be PASS — the chain is the same chain.
| JSON-RPC method | Legacy (XDPoSChain v2.6.8) | Modern (Geth v1.17.3) | Rule · not yet run |
|---|---|---|---|
| eth_chainId | 0x32 (50) ✓ | 0x32 (50) ✓ | PASS · const match |
| net_version | "50" ✓ | "50" ✓ | PASS · const match |
| eth_blockNumber | #103,427,225 | #103,427,225 | PASS · Δ = 0 blocks |
| eth_getBlockByNumber(0x0) | 0x4a9d…d6b1 | 0x4a9d…d6b1 | PASS · genesis bit-exact |
| eth_getBlockByNumber(0x1) | hash 0x2c48…ad4f stateRoot 0x49be…55ae | hash 0x2c48…ad4f stateRoot 0x49be…55ae | PASS · cross-chain bit-exact |
| eth_getBalance(0x…0088) | 0x877f0a6e8dd7273ab680000 | 0x877f0a6e8dd7273ab680000 | PASS · state parity |
| eth_feeHistory | baseFee 0x2e90edd00 (12.5 gwei) | baseFee 0x2e90edd00 (12.5 gwei) | PASS · XDC fixed base fee |
| net_peerCount | 31 peers | 29 peers | PASS · both healthy |
| eth_syncing | false | false | PASS · both at head |
| net_listening | true | true | PASS |
| txpool_status | {pending,queued} | {pending,queued} | PASS · shape parity |
| web3_clientVersion | XDC/v2.6.8-stable/linux-amd64/go1.23.12 | Geth/v1.17.3-stable-02ebae0d/linux-amd64/go1.24.0 | DIFF · intentional |
| eth_gasPrice | ~13.75 gwei (suggested, dynamic) | ~15.00 gwei (suggested, dynamic) | DIFF · oracle estimate |
| eth_protocolVersion | 0x64 (XDPoS proto 100) | deprecated in 1.17 | DIFF · expected |
| eth_getProof | N/A · -32601 | Merkle proof returned | MODERN · EIP-1186 |
| debug_dbAncients | N/A · -32601 | 103,318,253 (freezer cutoff) | MODERN · freezer/era-files |
Real-world verdict (not yet run)
Both endpoints are in perfect sync at block #103,427,225. Every consensus-touching field — genesis hash, block-1 hash, block-1 stateRoot, system-contract balance, base fee — is bit-identical. The modern node additionally serves eth_getProof and debug_dbAncients (the freezer-cutoff sentinel exposes that 103.3M of 103.4M blocks live in flat ancient files, leaving only the recent tail in the bounded PBSS live state).
Bit-exact, fork-aware, harness-enforced
Live RPC parity is the visible surface; the migration's release gate is bit-exact agreement on the consensus-critical bytes for every block on both networks. The harness replays mainnet blocks through both clients and asserts the three roots match — across normal blocks and every fork-activation boundary.
| Test | Range | Assertion | Latest run |
|---|---|---|---|
| State root parity | blocks 1 → head | stateRoot ≡ canonical | 103,288,114 / 103,288,114 PASS |
| Receipts root parity | blocks 1 → head | receiptsRoot ≡ canonical | 103,288,114 / 103,288,114 PASS |
| Block hash parity | blocks 1 → head | hash ≡ canonical | 103,288,114 / 103,288,114 PASS |
| XDPoS v1 → v2 switch | epoch boundary | consensus rule swap, hashes preserved | PASS |
| Berlin / London / Shanghai forks | activation blocks | EIP-2929 / 1559 / 3855 rules active | PASS |
| Masternode rotation | every epoch | validator set ≡ canonical | PASS |
| TRC21 fee routing | 200 sample txs | issuer pays gas, balances ≡ | 200 / 200 PASS |
| Reward distribution (90/10) | 10 random epochs | block reward split ≡ canonical | 10 / 10 PASS |
| Genesis hash | block 0 | 0x645a…d9c0 (mainnet) | PASS |
Zero consensus divergence on integration branch
Branch reset/integration-1.17.3 has replayed XDC mainnet to head with zero parity failures across all three roots. The modern binary serving the live endpoint above produces byte-identical blocks to the canonical XDPoSChain client.
What changes when the storage engine actually catches up
RPC latency, sync time, archive footprint and memory — measured on production-shape hardware (8 vCPU / 32 GB / NVMe), serving the same canonical XDC mainnet.
Complete source method reference
The source comparison defines these 18 read-only requests. The checker above intentionally reports a smaller connectivity sample. Method availability, latest-block differences and protected namespaces do not by themselves establish correctness or consensus parity.
| Method / source label | Parameters | Source test class | Expected value or compared field |
|---|---|---|---|
| web3_clientVersion | [] | diff | |
| eth_chainId | [] | const | 0x32 |
| net_version | [] | const | 50 |
| net_peerCount | [] | nonzero | |
| net_listening | [] | truthy | |
| eth_syncing | [] | falsy | |
| eth_blockNumber | [] | block | |
| eth_gasPrice (suggested) | [] | diff | |
| eth_protocolVersion | [] | diff | |
| eth_getBlockByNumber(0x0) · genesis | ["0x0", false] | genesis | |
| eth_getBlockByNumber(0x1) · stateRoot | ["0x1", false] | cross | hash |
| eth_getBalance(0x…88) | ["0x0000000000000000000000000000000000000088", "latest"] | cross | |
| txpool_status | [] | shape | |
| eth_feeHistory · baseFee 12.5 gwei | ["0x4", "latest", [25, 50, 75]] | basefee | |
| eth_getProof (EIP-1186) | ["0x0000000000000000000000000000000000000088", [], "latest"] | modern_only | |
| debug_dbAncients (freezer) | [] | modern_only | |
| eth_getLogs(block 0x1, all topics) | [{"fromBlock": "0x1", "toBlock": "0x1"}] | logs_cross | |
| eth_getTransactionByHash (block 50M tx) | ["0x1202fe3fe3b62a631f05d783df74b59f6176750d074560c8727cb4c8d3664339"] | tx_cross |
Interpretation and source limitations
The source row labelled stateRoot actually compares the block hash. Latest balances can refer to different blocks. A successful response is not an independent correctness proof. Debug methods are reference-only and are not required for the new public checker.
| Source classification | Meaning |
|---|---|
| const | Compare response with hardcoded source expected value. |
| diff | Expected to vary by client or oracle; source labels DIFF. |
| nonzero | Positive peer count indicates endpoint peers, not chain security. |
| truthy | Source expects true. |
| falsy | Source expects false. |
| block | Display observed height; source marks PASS without chain agreement check. |
| genesis | Compare with source hardcoded genesis hash. |
| cross | Compare the selected field or serialized value with another endpoint. |
| shape | Check only required response keys. |
| basefee | Compare first feeHistory base fee with source hardcoded value. |
| modern_only | Any successful result is labeled PASS by source; no substantive validation. |
| logs_cross | Compare entire JSON log arrays. |
| tx_cross | Compare transaction hash, blockHash and from fields. |
Original comparison configuration
{
"legacy": "https://rpc.xinfin.network",
"modern": "https://new.xdcrpc.com/",
"erigon": "https://02.xdcrpc.com/erigonrpc",
"mode": "http",
"expected": {
"chainIdHex": "0x32",
"netVersion": "50",
"baseFeeHex": "0x2e90edd00",
"genesisHash": "0x4a9d748bd78a8d0385b67788c2435dcdb914f98a96250b68863a1f8b7642d6b1"
},
"sampleAddress": "0x0000000000000000000000000000000000000088",
"qualification": "Source configuration only; no endpoint connection or current chain validation was performed."
}About this source
Publisher: XDC Innovation Labs. Contact: pq@xdcindia.com. This source-specific contact is separate from the replacement website operator.
Repository snapshot d2345a8 · Source content and historical measurements are attributed to XDC Innovation Labs. Links to independently operated services remain with their providers.