XChain Node: Architecture
Position in the Data Pipeline
xchain-node sits above all other XChain services. It does not participate in the data pipeline at runtime, instead, it provisions and manages the containers that form the pipeline:
flowchart TD
NODE["xchain-node<br>(CLI orchestrator)"]
COIN["Coin Node<br>(bitcoind)"]
DECODER["Decoder"]
INDEXER["Indexer"]
EXPLORER["Explorer"]
HUB["Hub"]
DOCKER["Docker containers + networks"]
NODE -->|installs / manages| COIN
NODE -->|installs / manages| DECODER
NODE -->|installs / manages| INDEXER
NODE -->|installs / manages| EXPLORER
NODE -->|installs / manages| HUB
COIN --> DOCKER
DECODER --> DOCKER
INDEXER --> DOCKER
EXPLORER --> DOCKER
HUB --> DOCKER
Each coin/network combination (e.g., bitcoin/regtest) gets its own Docker network. Shared services (database, hub, explorer) are connected to all coin/network networks.
Internal Components
flowchart TD
subgraph NODEBOX["xchain-node"]
CLI["cli.js<br>Commander<br>21 commands"]
MODOPS["moduleOperations.js<br>installModules / startModules /<br>stopModules / restartModules /<br>uninstallModules / resetModules"]
PRECHECK["precheck.js<br>Docker check<br>Dir creation<br>MariaDB open<br>Version fetch"]
MODSVC["ModuleService<br>cloneGit()<br>buildAndUp()<br>uninstallModule()"]
CONFIGSVC["ConfigService"]
DOCKERSVC["DockerService"]
DBSVC["DatabaseService"]
VERSIONSVC["VersionService"]
NODESVC["NodeService"]
BOOTSTRAPSVC["BootstrapService"]
MARIADBSTORE["MariaDbStore<br>modules tbl"]
STATEJS["state.js<br>singletons"]
CONSTANTS["constants<br>enums/paths"]
CLI --> MODOPS
CLI --> PRECHECK
MODOPS --> MODSVC
MODSVC --> CONFIGSVC
MODSVC --> DOCKERSVC
MODSVC --> DBSVC
VERSIONSVC --> CONFIGSVC
NODESVC --> DOCKERSVC
BOOTSTRAPSVC --> DBSVC
end
Source Files
| File | Purpose |
|---|---|
src/index.js |
Entry point: loads dotenv, calls parseCommand() |
src/cli.js |
Commander.js CLI definitions (21 commands, global options, preAction hook) |
src/precheck.js |
Pre-command validation (Docker, directories, MariaDB connection, versions, networks) |
src/state.js |
Singleton state (MariaDB pool instance, cached modules, verbose flag) |
src/MariaDbStore.js |
MariaDB-backed store for module to container ID persistence; persists mappings in the xchain_node.modules table inside the shared xchain-node-database container (the same container that managed services use for their decoder/indexer databases) |
src/config/constants.js |
Enums (Coin, Network, XChainService), paths, git URLs |
src/services/ConfigService.js |
Path/naming helpers, config generation, arg parsing, port validation |
src/services/DockerService.js |
Docker CLI wrappers (network, build, run, start, stop, exec, logs, monitor) |
src/services/ModuleService.js |
Git clone, Docker build/run, install/uninstall/update flows |
src/services/DatabaseService.js |
MariaDB container setup, user/password management, database creation |
src/services/StatusService.js |
Container status queries, version display, formatted table output |
src/services/VersionService.js |
Local/remote/container version checking via GitHub API |
src/services/NodeService.js |
Crypto node download and Docker image building |
src/services/HubService.js |
Hub installation, update, and JSON-RPC configuration |
src/services/ExplorerService.js |
Explorer installation and configuration |
src/services/BootstrapService.js |
Bootstrap snapshot create/restore with SHA-256 verification; creates Ed25519 signatures on bootstrap create when XCHAIN_NODE_BOOTSTRAP_SIGNING_KEY is set, and enforces signature verification on restore (fail-closed by default) |
src/services/TelemetryService.js |
Anonymous usage telemetry: collects install ID, version, running services, and OS info; sends to the hub collector; default-on with opt-out via --no-telemetry, XCHAIN_NODE_NO_TELEMETRY=1, or a persisted preference |
src/services/CredentialsService.js |
Persists per-OS-user MariaDB credentials in ~/.xchain-node/credentials.json; stores both the bundled-DB password and optional external-DB connection details |
src/services/DiscoveryService.js |
Auto-discovers existing xchain-node Docker containers and re-registers them in the MariaDB modules table (sync command); classifies containers by naming convention to recover state after a database loss |
src/services/ValidatorService.js |
Validator-mode onboarding: generates Ed25519 signing keys and writes validator config files (validator init); reads and displays persisted validator settings (validator status); injects resulting env vars into the hub container |
src/operations/moduleOperations.js |
Bulk operations (install/start/stop/restart/reset/exec/logs/monitor) |
src/HubConnector.js |
JSON-RPC 2.0 client for xchain-hub |
src/ExplorerConnector.js |
JSON-RPC 2.0 client for xchain-explorer |
src/TelemetryConnector.js |
HTTP client that posts telemetry pings to the central hub collector; URL overrideable via XCHAIN_NODE_TELEMETRY_URL |
| src/GitHubDownloader.js | GitHub release download with SHA-256 hash verification |
| src/utils/helpers.js | Utilities (sleep, stringToCoin, decompressTarGz) |
Precheck Workflow
Every command runs preCheck() before execution:
- Verify Docker is installed and accessible (
docker --version+docker ps) - Create runtime directories:
data/,modules/,tmp/,tmp/containers_files/ - Create base Docker network (
xchain-node) - Start or verify the shared MariaDB container
- Ensure the per-OS-user
xchain_nodedatabase credentials exist (viaCredentialsService: credentials are generated on first run and persisted in~/.xchain-node/credentials.jsonat mode 0600; on subsequent runs they are loaded from that file), then open a MariaDB connection - Scan running Docker containers and reconcile the
xchain_node.modulestable - Fetch remote service versions from GitHub (for install/update commands only)
- Query installed modules status
- Install or update xchain-hub
- Update hub and explorer configurations with current service endpoints (skipped for read-only commands)
flowchart TD
S1["1. Verify Docker installed and accessible"]
S2["2. Create runtime directories"]
S3["3. Create base Docker network"]
S4["4. Start or verify the shared MariaDB container"]
S5["5. Ensure per-OS-user xchain_node DB credentials exist,<br>open a MariaDB connection"]
S6["6. Scan running containers,<br>reconcile the xchain_node.modules table"]
S7["7. Fetch remote service versions from GitHub<br>(install/update commands only)"]
S8["8. Query installed modules status"]
S9["9. Install or update xchain-hub"]
S10["10. Update hub and explorer configurations<br>(skipped for read-only commands)"]
S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7 --> S8 --> S9 --> S10
Module State Schema
xchain-node uses a MariaDB table to map installed modules to their Docker container IDs. The table lives in the xchain_node database and is created automatically on first run:
CREATE TABLE IF NOT EXISTS modules (
module VARCHAR(64) NOT NULL,
coin VARCHAR(32) NOT NULL DEFAULT '',
network VARCHAR(32) NOT NULL DEFAULT '',
container_id VARCHAR(128) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (module, coin, network)
)
- Shared services (hub, explorer, database) use empty string for
coinandnetwork getAllModuleContainers(coin, network)always includes shared services in filtered resultsMariaDbStoreis the class that wraps this table; it replaced the previous LevelDB-based store
Runtime Directory Structure
xchain-node/
├── modules/ # Cloned XChain service repositories
│ ├── xchain-encoder/
│ ├── xchain-decoder/
│ ├── xchain-utxo-tracker/
│ ├── xchain-indexer/
│ ├── xchain-hub/
│ ├── xchain-explorer/
│ ├── xchain-regtest-miner/
│ └── xchain-e2e-test/
├── data/
│ ├── xchain_node/ # (legacy path; state now stored in MariaDB xchain_node.modules)
│ └── node/{coin}/{network}/ # Crypto node blockchain data
├── config/ # Per-coin/network config overrides
│ ├── bitcoin-mainnet
│ ├── bitcoin-testnet
│ ├── bitcoin-regtest
│ ├── dogecoin-mainnet
│ └── ... (9 files total, one per coin/network combo)
├── crypto_nodes/ # Crypto node Dockerfiles and configs
│ ├── bitcoin/
│ │ ├── Dockerfile
│ │ ├── bitcoin-mainnet.conf
│ │ ├── bitcoin-testnet.conf
│ │ └── bitcoin-regtest.conf
│ ├── dogecoin/
│ └── litecoin/
└── tmp/ # Temporary files during install/update
├── xchain-*/ # Temporary clones for version checking
└── containers_files/ # Staging area for docker cp operations
Docker Network Topology
Each coin/network combination gets its own Docker network. Shared services are connected to all networks:
flowchart TD
subgraph MAINNET["xchain-node-bitcoin-mainnet"]
MN_SVC["encoder, decoder, utxo-tracker, indexer, node"]
MN_DB[("database")]
MN_HUB["hub"]
MN_EXPLORER["explorer"]
MN_NOTE["shared, also connected to other nets"]
MN_DB --- MN_HUB --- MN_EXPLORER
MN_EXPLORER -.-> MN_NOTE
end
subgraph REGTEST["xchain-node-bitcoin-regtest"]
RT_SVC["encoder, decoder, utxo-tracker, indexer, node, regtest-miner"]
RT_DB[("database")]
RT_HUB["hub"]
RT_EXPLORER["explorer"]
RT_NOTE["same shared containers"]
RT_DB --- RT_HUB --- RT_EXPLORER
RT_EXPLORER -.-> RT_NOTE
end
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.