Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.11.0] - 2026-08-26

### Added
- Install and update end with a bootstrap restore summary, so a restore that did not happen is stated rather than left as one warning mid-log.
- `XCHAIN_NODE_FORCE_BOOTSTRAP=1` restores a published bootstrap over an already-populated service, for when the install that would have taken it failed.

### Changed
- The release manifest pins the v0.11.0 component set.

### Fixed
- The migration precondition refusal only prints a scoped migrate command when the running build is confirmed to support one, and otherwise names every migration an unscoped run would apply.
- `reset xchain-decoder` now refuses while an indexer is installed and names the `--with-indexer` joint form, because resetting one half of the pair leaves the other unable to commit blocks.
- The bitcoind mirror retry now answers the address-list form Node asks for, so the retry actually dials instead of failing immediately on every supported Node version.
- A bitcoind tarball already present at the download path is used and verified against the pinned hash rather than overwritten, so the manual workaround the failure message describes now works.
- The bootstrap restore summary is printed even when the install fails partway, which is when it matters most.
- A published bootstrap older than a week is called out during the download, since a snapshot that has aged past the chain can leave a service unable to continue from it.
- A failed bitcoind download now retries against the site's other mirror addresses, so one mirror serving a broken certificate chain no longer blocks the install.
- Download failures name the URL, the mirror and the cause instead of a generic message.
- Module clones now use public HTTPS URLs, so installs work without a GitHub SSH key.
- Downloading a coin node now creates the crypto-nodes directory first, fixing installs pointed at a fresh custom volume.
- Bootstrap auto-restore downloads now recover a root-owned destination directory instead of failing with a permission error.
- The explorer install health wait now allows about two minutes of container warm-up instead of ten seconds.

## [0.10.0] - 2026-08-22

### Added
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
<img src="https://img.shields.io/badge/coverage-unit%20%7C%20integration%20%7C%20e2e%20%7C%20smoke%20%7C%20boundary%20%7C%20security%20%7C%20fuzz%20%7C%20chaos%20%7C%20regression%20%7C%20performance%20%7C%20mutation-brightgreen" alt="Coverage">
</p>

CLI management and orchestration tool for the XChain Platform. Installs, configures, and manages all XChain services and coin nodes (bitcoind, litecoind, dogecoind) as Docker containers. Generates per-service environment variables from a two-layer configuration system, manages LevelDB state, provisions MariaDB databases, and provides multi-pane log monitoring.
CLI management and orchestration tool for the XChain Platform. Installs, configures, and manages all XChain services and coin nodes (bitcoind, litecoind, and dogecoind today; any Bitcoin-RPC-compatible UTXO chain can be added by configuration) as Docker containers. Generates per-service environment variables from a two-layer configuration system, manages LevelDB state, provisions MariaDB databases, and provides multi-pane log monitoring.

## Features

- **Multi-chain orchestration**: manages Bitcoin, Litecoin, and Dogecoin across mainnet, testnet, and regtest; each chain/network gets its own Docker network and container set
- **Multi-chain orchestration**: manages Bitcoin, Litecoin, and Dogecoin today across mainnet, testnet, and regtest; each chain/network gets its own Docker network and container set
- **Order-independent argument parsing**: CLI arguments auto-classified as service, coin, network, or branch name regardless of position
- **Docker container lifecycle**: install, start, stop, restart, update, uninstall, and reset services with single commands
- **Configuration generation**: two-layer system (hardcoded defaults + config file overrides) producing 40+ environment variables per service
- **Crypto node management**: downloads Bitcoin Core, Litecoin, and Dogecoin binaries from official sources with SHA-256 verification; includes per-chain regtest tuning applied automatically
- **Crypto node management**: downloads the Bitcoin Core, Litecoin, and Dogecoin binaries (the chains supported today) from official sources with SHA-256 verification; includes per-chain regtest tuning applied automatically
- **Database orchestration**: provisions shared MariaDB, creates per-service databases and users with subnet-based permissions
- **Bootstrap snapshots**: create and restore gzipped snapshots of UTXO tracker, decoder, and indexer data; integrity is double-verified with SHA-256 checksums and a detached Ed25519 signature pinned to a bundled public key
- **Validator mode**: `validator init` generates an Ed25519 signing key and capabilities config; the hub boots in PBFT validator mode when a key is present
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "xchain-node",
"version": "0.10.0",
"version": "0.11.0",
"description": "xchain-node allows users to install, configure and run XChain platform nodes.",
"license": "AGPL-3.0-or-later",
"repository": {
Expand Down
4 changes: 3 additions & 1 deletion src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,10 @@ gate could report them, so the cron exited 0 while a consumer archive went stale
.argument('<chain>', '(bitcoin, litecoin, dogecoin)')
.argument('<network>', '(mainnet, testnet, regtest)')
.option('--yes', 'Skip the destructive-reset confirmation prompt (for CI/scripted resets)')
.option('--with-indexer', 'Reset xchain-indexer alongside xchain-decoder; the pair is only coherent when both move together')
.action(async (service, chain, network, options) => {
const confirmed = await resetModules(service, chain, network, !!(options && options.yes))
const confirmed = await resetModules(service, chain, network,
!!(options && options.yes), !!(options && options.withIndexer))
return process.exit(confirmed ? 0 : 1)
})

Expand Down
17 changes: 9 additions & 8 deletions src/coins/BTC.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ module.exports = {
GAS: '1XChain3M4uRwcHqt4XuhVBUQ8cL4qQsA',
DONATE1: '1Donate1GERVKPW6GFQcnGeTa8dgL6Abyp', // Protocol Development
DONATE2: '1Donate2LkbBrsanwCVRPWZCXAqQcvcqGz', // Community Development
FEE_DESTINATION: '1FeesxM9LTEjBYVTkynK6jfDBgvksuh2WL', // native-fee destination (env-overridable)
REWARD: '1rewardsZAyeuLeFJKoAepYiNN5N6uSzn', // validator reward pool (COLLECT)
FEE_DESTINATION: '1FeesxM9LTEjBYVTkynK6jfDBgvksuh2WL', // native-fee destination (regtest-only env override; ignored on mainnet/testnet)
REWARD: '1RewardsRQTXMAytLt4bBQvPEscKsSEXt', // validator reward pool (COLLECT)
EXPLORER: '1Donate3GBGSZzzrS9U9gUgURYKscAE6Yn', // display-only donation; not read by indexer
},
// Genesis ledger bootstrap pin (Counterparty name carry-forward).
Expand Down Expand Up @@ -166,12 +166,13 @@ module.exports = {
minStandardTxNonWitnessSize: 82,
singleOpReturnPolicy: true,
},
// Fresh testnet genesis 2026-08-10 (operator): was 138000. Raised to
// just under the live tip (147799 at the decision) so the chain starts
// effectively empty and replays in seconds. Consensus input (folded
// into consensusSubset), so it moves the BTC testnet pin and ships in
// one wave with every other vendoring service.
firstBlock: 147500,
// Fresh testnet genesis 2026-08-24 (operator): was 147500 (the
// 2026-08-10 genesis). Raised to just under the live tip (149703 at
// the decision) so the public testnet announces with zero
// pre-announcement test actions and replays in seconds. Consensus
// input (folded into consensusSubset), so it moves the BTC testnet
// pin and ships in one wave with every other vendoring service.
firstBlock: 149700,
// Block-0 hash of the chain (see mainnet above). Unpinned until the operator
// reads it off the fleet's own node: `bitcoin-cli -testnet getblockhash 0`.
// This is the one value that separates testnet3 from testnet4, which the
Expand Down
16 changes: 8 additions & 8 deletions src/coins/DOGE.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module.exports = {
GAS: 'DGasfpttCnTijuuoAdiJ9sXJjG7vQ5pMkW',
DONATE1: 'DDonate1RBcwGnCRNnVtwuCmQyWW1Gn25f', // Protocol Development
DONATE2: 'DDonate2o3Sg4phybp92oFpkmv8S9ZhGSV', // Community Development
FEE_DESTINATION: 'DFeesjvoMoVqd9UDuwDSAxzHMF5xZFgeG9', // native-fee destination (env-overridable)
FEE_DESTINATION: 'DFeesjvoMoVqd9UDuwDSAxzHMF5xZFgeG9', // native-fee destination (regtest-only env override; ignored on mainnet/testnet)
REWARD: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', // structural only; COLLECT/XCHAIN are BTC-only
EXPLORER: 'DDonate3FCoUgi1bxW5r9c2p75uKTLw9qE', // display-only donation
},
Expand Down Expand Up @@ -111,13 +111,13 @@ module.exports = {
supportsSegwit: false,
singleOpReturnPolicy: true,
},
// Fresh testnet genesis 2026-08-10 (operator): was 64800000, which is
// ~3.02M blocks behind the tip and ~21 hours of replay - the single
// reason this genesis is worth doing. Raised to just under the live
// tip (67819590 at the decision) so replay is minutes. Consensus input
// (folded into consensusSubset), so it moves the DOGE testnet pin and
// ships in one wave with every other vendoring service.
firstBlock: 67815000,
// Fresh testnet genesis 2026-08-24 (operator): was 67815000 (the
// 2026-08-10 genesis). Raised to just under the live tip (67847591 at
// the decision) so the public testnet announces with zero
// pre-announcement test actions and replays in minutes. Consensus
// input (folded into consensusSubset), so it moves the DOGE testnet
// pin and ships in one wave with every other vendoring service.
firstBlock: 67847500,
// Block-0 hash of the chain (see mainnet above). Unpinned until the operator
// reads it off the fleet's own node: `dogecoin-cli -testnet getblockhash 0`.
chainGenesisHash: null,
Expand Down
15 changes: 8 additions & 7 deletions src/coins/LTC.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module.exports = {
GAS: 'LXChainCN6yjHVqqS9tYzYVYZ8CCZcSx72',
DONATE1: 'Ldonate18tNZcVThKm5MX33EjvhaanJ6Mg', // Protocol Development
DONATE2: 'Ldonate2io846q2e7q8dUArh3TNnaq9ENb', // Community Development
FEE_DESTINATION: 'Lfees7tszAx5Gqam2fuqf6biaX3LXafM4H', // native-fee destination (env-overridable)
FEE_DESTINATION: 'Lfees7tszAx5Gqam2fuqf6biaX3LXafM4H', // native-fee destination (regtest-only env override; ignored on mainnet/testnet)
REWARD: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', // structural only; COLLECT/XCHAIN are BTC-only
EXPLORER: 'Ldonate3FfyqbYQAYxo3qjFLcu28oUdAfn', // display-only donation
},
Expand Down Expand Up @@ -109,12 +109,13 @@ module.exports = {
minStandardTxNonWitnessSize: 85,
singleOpReturnPolicy: true,
},
// Fresh testnet genesis 2026-08-10 (operator): was 4765000. Raised to
// just under the live tip (4855452 at the decision) so the chain
// starts effectively empty and replays in seconds. Consensus input
// (folded into consensusSubset), so it moves the LTC testnet pin and
// ships in one wave with every other vendoring service.
firstBlock: 4855000,
// Fresh testnet genesis 2026-08-24 (operator): was 4855000 (the
// 2026-08-10 genesis). Raised to just under the live tip (4862567 at
// the decision) so the public testnet announces with zero
// pre-announcement test actions and replays in seconds. Consensus
// input (folded into consensusSubset), so it moves the LTC testnet
// pin and ships in one wave with every other vendoring service.
firstBlock: 4862500,
// Block-0 hash of the chain (see mainnet above). Unpinned until the operator
// reads it off the fleet's own node: `litecoin-cli -testnet getblockhash 0`.
chainGenesisHash: null,
Expand Down
13 changes: 10 additions & 3 deletions src/coins/consensus_pin.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,17 @@ module.exports = {
// all three testnet hashes move and the one-wave rule above applies in full.
// Regtest and mainnet are untouched, and their hashes were re-verified
// against the canonical files as unchanged by this edit.
//
// REGENERATED 2026-08-24 (fresh testnet genesis, operator): testnet
// `firstBlock` moved to just under the live tip on all three chains
// (BTC 147500 -> 149700, LTC 4855000 -> 4862500, DOGE 67815000 -> 67847500)
// so the public testnet announces with zero pre-announcement test actions.
// Same one-wave rule as every regeneration above. Regtest and mainnet are
// untouched and were re-verified as unchanged by this edit.
testnet: {
BTC: '1e45a958ff9eb6a88be8684e3801b57e7afcfc9031f7761e4f4b1dcf1c8d42a9',
LTC: '888818a874d6d8acb3363355089f0de601c355b63fc8431a44ef666f91615202',
DOGE: 'ea3ee0d1407959f3cb59e4baf66b50dfc2ada9962351e578d7c6d8586e6ff905',
BTC: 'f6589c6b88dc930db05998070ef0b73743f58623a0d23fbc30fdb158c49d1427',
LTC: '9faf066a1470be2486d8a2cd121548ca02de1397d0678a2ab8dc0e712ebfa8fd',
DOGE: '2991d7e7caf2b212de959dd5831ac1477e0b13da95ac1ed8c2b43e2704732439',
},

regtest: {
Expand Down
27 changes: 15 additions & 12 deletions src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,23 +96,26 @@ const projectFolders = {
"xchain-vm": "XChainVM"
}

// HTTPS, not SSH: the repos are public, and a fresh machine has no GitHub SSH
// key, so git@ URLs fail the very first module clone of a documented install.
// SSH/fork/local-source workflows go through XCHAIN_NODE_MODULES_URLS_OVERRIDE.
const modulesUrls = {
"xchain-encoder": "git@github.com:XChain-Platform/xchain-encoder.git",
"xchain-decoder": "git@github.com:XChain-Platform/xchain-decoder.git",
"xchain-utxo-tracker": "git@github.com:XChain-Platform/xchain-utxo-tracker.git",
"xchain-indexer": "git@github.com:XChain-Platform/xchain-indexer.git",
"xchain-regtest-miner": "git@github.com:XChain-Platform/xchain-regtest-miner.git",
"xchain-hub": "git@github.com:XChain-Platform/xchain-hub.git",
"xchain-explorer": "git@github.com:XChain-Platform/xchain-explorer.git",
"xchain-e2e-test": "git@github.com:XChain-Platform/xchain-e2e-test.git",
"xchain-sync": "git@github.com:XChain-Platform/xchain-sync.git",
"xchain-vm": "git@github.com:XChain-Platform/xchain-vm.git",
"xchain-encoder": "https://github.com/XChain-Platform/xchain-encoder.git",
"xchain-decoder": "https://github.com/XChain-Platform/xchain-decoder.git",
"xchain-utxo-tracker": "https://github.com/XChain-Platform/xchain-utxo-tracker.git",
"xchain-indexer": "https://github.com/XChain-Platform/xchain-indexer.git",
"xchain-regtest-miner": "https://github.com/XChain-Platform/xchain-regtest-miner.git",
"xchain-hub": "https://github.com/XChain-Platform/xchain-hub.git",
"xchain-explorer": "https://github.com/XChain-Platform/xchain-explorer.git",
"xchain-e2e-test": "https://github.com/XChain-Platform/xchain-e2e-test.git",
"xchain-sync": "https://github.com/XChain-Platform/xchain-sync.git",
"xchain-vm": "https://github.com/XChain-Platform/xchain-vm.git",
// Not an installable service; listed so LIBRARY_BUNDLES can stage it
// into the xchain-e2e-test build context (test:sdk suites).
"xchain-sdk": "git@github.com:XChain-Platform/xchain-sdk.git",
"xchain-sdk": "https://github.com/XChain-Platform/xchain-sdk.git",
// Also not installable; staged into the e2e-test build context so the
// template suites (amm/escrow/crowdsale/vesting) can load their source.
"xchain-contracts": "git@github.com:XChain-Platform/xchain-contracts.git"
"xchain-contracts": "https://github.com/XChain-Platform/xchain-contracts.git"
}

// Optional env-var override for local-source workflows. Lets you point any
Expand Down
Loading
Loading