Database replication service for the XChain Platform. Syncs indexer and decoder databases to validators and other consumers via REST snapshots and real-time WebSocket streaming, enabling lightweight validators that don't need to run full decoder+indexer stacks.
Breaking API change (2026-05): REST and WebSocket paths now carry a
/:dbType/segment (indexerordecoder). For example:/status/indexer/BTC/mainnet,WS /subscribe/decoder/BTC/mainnet. The bare/statusendpoint now returns a nested{coin: {network: {dbType: {...}}}}structure. Clients must update their URLs. Transparency endpoints return HTTP 400 fordbType=decoder(decoder has no transparency log by design).
- Dual mode: server mode serves data from authoritative indexer and decoder databases; client mode replicates both into local MariaDB instances
- Multi-chain single instance: discovers all installed chains/networks via the hub and serves them from one process on one port
- Hub auto-discovery: calls xchain-hub
getallconfigsat startup; re-polls every 5 minutes to detect newly installed chains - Dual DB type support: syncs both the indexer DB (full ledger) and decoder DB (8 of 9 tables;
TransparencyLogandmempool_transactionsexcluded by design) behind a/:dbType/path segment - Schema auto-replication: client fetches DDL from the server before data, creating tables in the replica with DDL whitelisted to
CREATE TABLEonly - Full snapshot export: compressed, streamed JSON database dumps for bootstrapping new validators
- Incremental snapshots: delta exports since any block height for catch-up after downtime
- Real-time WebSocket streaming: per-chain/network/dbType subscriptions for new blocks and reorg events
- Hash chain verification: per-block chained SHA-256 hashes (ledger, actions, contracts for indexer; block_hash for decoder) validated on apply
- Cross-source comparison: clients can sync from 2+ independent servers and hold blocks until all sources confirm identical hashes
- Transparency log: append-only per-block hash record with SHA-256 Merkle epoch roots and inclusion proofs (indexer only)
- SPV state-commitment recompute: apply-time rebuild of per-block light-client roots (
state_tree_roots/state_tree_nodes) that halts on divergence from the source (indexer only, opt-out viaVERIFY_STATE_COMMITMENT=false) - Checkpoint-quorum anchor: optional federation anchor that fetches the server's quorum-signed checkpoint, verifies it against a pinned validator set, and asserts the committed state root matches the replica's own recomputed value (indexer only, opt-in via
VERIFY_CHECKPOINT_QUORUM=true) - Rate limiting: configurable per-IP limits on snapshot downloads and WebSocket connections
- Reorg propagation: detects chain reorganizations from the source database and broadcasts rollback events to all subscribers, then rolls back the replica
- Automatic catch-up: clients detect block gaps on reconnect and self-heal via incremental REST snapshots
- Circuit-breaker DB connections: automatic failure detection and recovery with configurable thresholds
- Input validation: SQL identifier sanitization, DDL whitelisting, WebSocket event schema validation
- 1850+ tests: unit, integration, e2e, boundary, security, fuzz, chaos, mutation, regression, performance, smoke
Full xchain-sync documentation is available in the xchain-documentation repository:
| Document | Description |
|---|---|
| README | Overview, installation, quick start, scripts, dependencies |
| Architecture | Data pipeline position, dual-mode design, internal components, sync algorithms |
| Configuration | Environment variables, hub discovery, database naming |
| Operations | Running, Docker, resilience, troubleshooting |
| API Reference | REST snapshot/status/schema endpoints and the WebSocket streaming protocol |
git clone https://github.com/XChain-Platform/xchain-sync.git
cd xchain-sync
npm installCreate a .env file:
SYNC_MODE=server
SYNC_API_PORT=3006
# Allowed CORS origin (defaults to disabled when unset)
# CORS_ORIGIN=https://your-dashboard.example.com
HUB_API_HOST=localhost
HUB_PORT=10000
# Max time (ms) to wait for the hub at startup before exiting non-zero.
# Defaults to 300000 (5 min). Raise it for environments that intentionally
# bring the hub up after sync.
# MAX_HUB_WAIT_MS=300000In server mode, database credentials are discovered automatically from the hub. No database environment variables are needed. The service calls getallconfigs on the hub and connects to every installed indexer database.
For client mode:
SYNC_MODE=client
SYNC_API_PORT=3006
SYNC_SOURCES=http://sync1.example.com:3006,http://sync2.example.com:3006
VERIFY_HASHES=true
# Allowed CORS origin (defaults to disabled when unset)
# CORS_ORIGIN=https://your-dashboard.example.com
REPLICA_DB_HOST=127.0.0.1
REPLICA_DB_PORT=3306
REPLICA_DB_USER=xchain_sync
REPLICA_DB_PASS=your_password
HUB_API_HOST=localhost
HUB_PORT=10000
# Max time (ms) to wait for the hub at startup before exiting non-zero.
# Defaults to 300000 (5 min). Raise it for environments that intentionally
# bring the hub up after sync.
# MAX_HUB_WAIT_MS=300000Start the service:
npm run api| Command | Description |
|---|---|
npm run api |
Start the sync service |
bin/run-db-tiers.sh |
Run the DB-backed tiers against a throwaway MariaDB it starts and drops |
npm test |
Run unit tests |
npm run ci |
Unit tests plus the security tier, exits on completion |
npm run coverage |
Unit tests under c8 coverage instrumentation |
npm run test:boundary |
Boundary condition tests (consensus constants) |
npm run test:regression |
Unit tests tagged @regression |
npm run test:smoke |
Smoke tests (server + client startup, config loading) |
npm run test:integration |
Integration tests (requires MariaDB + running indexer) |
npm run test:e2e |
End-to-end tests (full server/client lifecycle) |
npm run test:security |
Security tests (validation, injection, auth) |
npm run test:fuzz |
Fuzz tests (property-based via fast-check) |
npm run test:fuzz:tier1 |
Tier 1 fuzz (client applier, hash verifier) |
npm run test:fuzz:tier2 |
Tier 2 fuzz (rollback, server poller, hub client) |
npm run test:fuzz:tier3 |
Tier 3 fuzz (config parsing) |
npm run test:fuzz:quick |
Quick fuzz (100 iterations) |
npm run test:chaos |
Chaos engineering tests (DB failures, network partitions) |
npm run test:perf |
Performance tests (throughput, snapshots, scaling) |
npm run test:perf:quick |
Quick perf (50 blocks) |
npm run test:mutate |
Mutation tests (Stryker) |
npm run test:mutate:quick |
Quick mutation tests |
npm run test:mutate:check |
Incremental mutation tests |
The unit tier runs anywhere. The integration and e2e tiers need a MariaDB, the
canonical indexer and decoder schemas from their sibling repositories, and five
environment variables. bin/run-db-tiers.sh supplies all of it: it starts a
throwaway tmpfs-backed MariaDB, resolves the siblings, runs the tier and drops the
container again.
bin/run-db-tiers.sh # integration tier
bin/run-db-tiers.sh integration e2e # both
bin/run-db-tiers.sh -- test/integration/replication-insert-shape.test.jsWhen both siblings resolve it also sets XCHAIN_REQUIRE_SIBLINGS=1, which is what
stops the cross-repo drift guards reporting green by skipping: several of them are
no-ops without a sibling checkout. Needs Docker; DB_PORT moves the host port off the
default 23316.
| Type | Tests | Description |
|---|---|---|
| Unit - Core | ~1,236 | SyncService.test.js, ServerPoller.test.js, BlockBroadcaster.test.js, ClientSync.test.js, ClientApplier.test.js, ClientRollback.test.js, HashVerifier.test.js, HubClient.test.js, TransparencyLog.test.js, SnapshotBuilder.test.js, config.test.js, utility.test.js |
| Boundary | ~171 | Block index limits, poll limits, config parsing, reorg detection, WebSocket limits, hash continuity, transparency pagination, batch insert, rollback scope, circuit breaker, source arrays, consensus constants |
| Security | ~140 | Input validation, SQL injection, DDL whitelisting, API auth, WebSocket auth, client sync safety, applier safety |
| Regression | ~4 | Curated consensus-constants regression suite |
| Smoke | ~17 | Server + client startup, config loading, liveness |
| Fuzz | ~55 | Property-based testing via fast-check: client applier, hash verifier, rollback, server poller, hub client, config |
| Chaos | 38 | Source DB resilience, replica DB resilience, sync resilience, network partitions |
| Integration | ~96 | Server polling, REST API, WebSocket streaming, client bootstrap, live sync, rollback, transparency log, lifecycle |
| E2E | ~63 | Full lifecycle, delta sync, multi-chain, reorg propagation, API endpoints |
| Performance | 8 suites | Payload throughput, snapshot performance, bootstrap apply, subscriber scaling, sustained sync, incremental catchup, rollback performance, bootstrap stampede |
| Total | ~1,850+ |
Copyright © 2025-2026 Dankest, LLC
Based on XChain Platform by Dankest, LLC – https://dankest.llc
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later) with a commercial license available for proprietary use.
You may use, modify, and distribute this material under the terms of the License. See LICENSE and NOTICE for full terms. See the licensing overview.