Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
ce72750
Merge master (v0.23.0 release) back into develop
jdogresorg Oct 12, 2026
e08d36b
Refuse cross-major release downgrades
jdogresorg Oct 12, 2026
02e8eb0
Split downgrade floor tests into short describe blocks
jdogresorg Oct 12, 2026
09c12df
Merge: Split downgrade floor tests into short describe blocks
jdogresorg Oct 12, 2026
df1dd28
Fix 14 review findings in xchain-node
jdogresorg Oct 12, 2026
15617b9
Pass host INDEX_MAP_PARITY_CHECK through to the sync server container
jdogresorg Oct 12, 2026
8b8d255
Scope INDEX_MAP_PARITY_CHECK passthrough to the sync module
jdogresorg Oct 12, 2026
cd8c313
Split sync passthrough out of configureSharedAfterHubKey
jdogresorg Oct 12, 2026
567e2c9
sync trunk
jdogresorg Oct 12, 2026
1183b8f
Exercise sync passthrough through container config
jdogresorg Oct 12, 2026
7cd1075
Merge: Exercise sync passthrough through container config
jdogresorg Oct 12, 2026
18db87c
Refresh audited production dependencies
jdogresorg Oct 12, 2026
fb1a5ff
Replace vulnerable Bitcoin signing dependencies
jdogresorg Oct 12, 2026
3269ccb
Merge: Replace vulnerable Bitcoin signing dependencies
jdogresorg Oct 12, 2026
fd309ba
Honour configured indexer DB name in bootstrap restore rehearsal
jdogresorg Oct 13, 2026
2d7a06b
Record the tracker archive height from the frozen store
jdogresorg Oct 13, 2026
b993117
Bring CLI commands module back under the 400 line limit
jdogresorg Oct 13, 2026
6007234
Bring tracker archive height files under the readability limits
jdogresorg Oct 13, 2026
c3559b1
Refuse decoder/indexer buildAndUp that would share the default extern…
jdogresorg Oct 13, 2026
92636ac
Bring build_and_up.js back under the 400 line limit
jdogresorg Oct 13, 2026
05a39bc
Declare the message-signing overrides and restore elliptic in the lock
jdogresorg Oct 13, 2026
a5fffc6
Stub the published host-port probe in the chaos module harnesses
jdogresorg Oct 13, 2026
75d9348
Merge: Bring CLI commands module back under the 400 line limit
jdogresorg Oct 13, 2026
b4a9eab
Merge: Bring tracker archive height files under the readability limits
jdogresorg Oct 13, 2026
70b85e5
Merge: Bring build_and_up.js back under the 400 line limit
jdogresorg Oct 13, 2026
5a114f5
Scope module database and DB user names to a non-default NODE_PREFIX
jdogresorg Oct 13, 2026
564f4a4
Keep getDefaultConfig within the function length limit
jdogresorg Oct 13, 2026
860b29c
Merge: Keep getDefaultConfig within the function length limit
jdogresorg Oct 13, 2026
8fdb9b7
Read migration precondition ledger from the configured database name
jdogresorg Oct 13, 2026
20bf629
Pass regtest gate switches through the node config
jdogresorg Oct 13, 2026
7fee74a
Split the configured database name lookup out of the precondition guard
jdogresorg Oct 13, 2026
503c0ce
Hoist hub passthrough lists out of configureHubBeforeKey
jdogresorg Oct 13, 2026
d431cf1
Merge: Split the configured database name lookup out of the precondit…
jdogresorg Oct 13, 2026
9c18731
sync trunk
jdogresorg Oct 13, 2026
ca806e5
Trim networks.js to the 400 line file limit
jdogresorg Oct 13, 2026
b3a03a3
Merge: Trim networks.js to the 400 line file limit
jdogresorg Oct 13, 2026
219ab75
fix(discovery): classify containers by name only, never by image
jdogresorg Oct 13, 2026
2caf0fa
Bump js-yaml to 4.3.2 and brace-expansion in the lockfile
jdogresorg Oct 13, 2026
158dc10
Pass publish switches through the hub host passthrough
jdogresorg Oct 13, 2026
7ad4645
Keep networks.js at the 400 line file limit
jdogresorg Oct 13, 2026
dfe11db
Merge: Keep networks.js at the 400 line file limit
jdogresorg Oct 13, 2026
df2bfac
Route contributions to develop and guard master against non-release p…
jdogresorg Oct 13, 2026
9e586b3
Kill the gpg agent when the gpg tests clean up their temp home
jdogresorg Oct 14, 2026
e289177
Merge: Kill the gpg agent when the gpg tests clean up their temp home
jdogresorg Oct 14, 2026
e6f1447
Budget and disambiguate NODE_PREFIX database scope, route reset throu…
jdogresorg Oct 14, 2026
6eef5c3
Prove NODE_PREFIX database scope end to end in the unit suite
jdogresorg Oct 14, 2026
97cf388
Hoist the crypto require and split the NODE_PREFIX scope suite into n…
jdogresorg Oct 14, 2026
801b82b
Show NOT READY in ps from the indexer and decoder readiness verdicts
jdogresorg Oct 14, 2026
1b70fd2
Merge remote-tracking branch 'origin/develop' into land-node-ready
jdogresorg Oct 14, 2026
cef003a
Build and sign the DOGE signer's reveal before broadcasting its commi…
jdogresorg Oct 14, 2026
010513d
Fix review round findings for xchain-node (2026-10-14)
jdogresorg Oct 14, 2026
462efeb
Default the bundled MariaDB buffer pool to 1G and keep it overridable
jdogresorg Oct 15, 2026
b9f9246
Re-vendor coin registry for the mainnet genesis re-pin
jdogresorg Oct 17, 2026
d893578
Preserve unreadable command locks
jdogresorg Oct 17, 2026
479e5b5
test: cover split config service modules
jdogresorg Oct 17, 2026
bd7803a
test config service modules directly
jdogresorg Oct 17, 2026
05911a3
Keep lock permission tests structurally scoped
jdogresorg Oct 17, 2026
6b4daf2
Tighten command lock documentation
jdogresorg Oct 17, 2026
458d66a
test: keep config module suites within structure limits
jdogresorg Oct 17, 2026
4f665d6
split config module test suites
jdogresorg Oct 17, 2026
4387d44
classify module test artifacts
jdogresorg Oct 17, 2026
7de8a6d
test: classify generated config module suites
jdogresorg Oct 17, 2026
130097c
Merge: Tighten command lock documentation
jdogresorg Oct 17, 2026
ad83bb3
Merge: classify module test artifacts
jdogresorg Oct 17, 2026
1ad47d1
Merge: test: classify generated config module suites
jdogresorg Oct 17, 2026
4386c47
Merge master into develop to level it before the v0.24.0 cut
jdogresorg Oct 17, 2026
b634793
Release v0.24.0
jdogresorg Oct 17, 2026
4c9a428
Release v0.24.0 manifest
jdogresorg Oct 17, 2026
47447e4
Let the downgrade override test follow the bundled manifest release
jdogresorg Oct 17, 2026
d82a947
Merge pull request #71 from XChain-Platform/release-manifest-v0.24.0
jdogresorg Oct 17, 2026
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
4 changes: 4 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<!-- Thanks for contributing to XChain Platform. -->

## Base branch

- [ ] This pull request targets `develop`. `master` only takes release merges, and a pull request into it from a fork cannot be merged.

## What this changes

<!-- One or two sentences on what changed and why. Link an issue if there is one. -->
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
# so the merge commit a release tag points at has its own green run.
branches: [master, develop]
pull_request:
branches: [master]
branches: [master, develop]

jobs:
ci:
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.24.0] - 2026-10-17

### Added
- Scoped module database and user names to a non-default node prefix and proved the scope end to end.
- Showed NOT READY in the process list from the indexer and decoder readiness verdicts.

### Changed
- Defaulted the bundled MariaDB buffer pool to 1G and kept it overridable.
- Refused cross-major release downgrades and decoder or indexer setups that would share the default external database name.

### Fixed
- Built and signed the DOGE signer's reveal before broadcasting its commit, and kept the signed reveal when only its broadcast fails.
- Classified containers by name only and preserved unreadable command locks.

### Security
- Replaced vulnerable Bitcoin signing dependencies and bumped js-yaml and brace-expansion.

### Changed
- Started the bundled MariaDB with a 1G InnoDB buffer pool by default, settable with `XCHAIN_NODE_DB_BUFFER_POOL_SIZE`.

## [0.23.0] - 2026-10-11

### Added
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ Match the existing log style: a concise subject line, then a short body explaini

## Pull requests

Fork the repository, branch off `develop`, and open your pull request against `develop`. Keep history linear (rebase, don't merge). `master` is what production runs and only ever receives release merges from `develop`; a pull request into `master` from a fork or any other branch fails the `base-branch guard` check and cannot be merged.

CI is the unit gate. Before opening a PR:

1. Run the no-external-services tiers (`npm run ci`, `npm run test:security`) and confirm they pass.
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ membership on the explorer, is `xchain-documentation/operations/run-a-validator.

## Host environment variables

Five env vars override where xchain-node stores its filesystem state. Set them in the shell or systemd unit before running `xchain-node install`. Each falls back to a path inside this repo if unset, so existing installs are unaffected.
Six env vars override where xchain-node stores its filesystem state. Set them in the shell or systemd unit before running `xchain-node install`. The data, temporary, modules, crypto-node, and config directories fall back to paths inside this repo if unset, so existing installs are unaffected. The command lock defaults to `~/.xchain-node/command.lock`.

| Variable | What goes here |
|---|---|
Expand All @@ -120,31 +120,32 @@ Five env vars override where xchain-node stores its filesystem state. Set them i
| `XCHAIN_NODE_MODULES_DIR` | Git clones of sibling xchain-* repos |
| `XCHAIN_NODE_CRYPTO_NODES_DIR` | Downloaded coin-node binaries |
| `XCHAIN_NODE_CONFIG_DIR` | Generated per-service `.env` files |
| `XCHAIN_NODE_LOCK_DIR` | Directory for the cross-process command lock (`command.lock` and its reclaim marker) |

On boxes with a small `/` partition and a large data volume (e.g., OVH RISE-3 with `/misc`), point `DATA_DIR` and `TMP_DIR` at the large volume before installing. Full docs in [CONFIGURATION.md](https://github.com/XChain-Platform/xchain-documentation/blob/master/components/node/configuration.md).

### Bundled MariaDB tuning

When xchain-node manages its own MariaDB container, these optional env vars override server defaults. They are applied as `mysqld` startup args at install time, so they **persist across a container recreate** (a `conf.d` file edited inside a running container does not). Each is unset by default so image defaults remain unchanged. Set them before `xchain-node install`.
When xchain-node manages its own MariaDB container, these optional env vars override server defaults. They are applied as `mysqld` startup args at install time, so they **persist across a container recreate** (a `conf.d` file edited inside a running container does not). Each is unset by default so image defaults remain unchanged, except `XCHAIN_NODE_DB_BUFFER_POOL_SIZE`, which defaults to `1G` (a value that is not digits with an optional `K`, `M` or `G` suffix logs a warning and falls back to `1G`), and `XCHAIN_NODE_DB_MAX_CONNECTIONS`, which defaults to `1000`. Set them before `xchain-node install`.

| Variable | mysqld setting | When to set |
|---|---|---|
| `XCHAIN_NODE_DB_DATA_DIR` | datadir bind-mount (`-v <dir>:/var/lib/mysql`) | Pin the datadir to a fast NVMe mount instead of the Docker data-root |
| `XCHAIN_NODE_DB_BUFFER_POOL_SIZE` | `innodb-buffer-pool-size` (e.g. `16G`) | Large/multi-DB hosts where the stock 128 MB thrashes on multi-GB datasets |
| `XCHAIN_NODE_DB_BUFFER_POOL_SIZE` | `innodb-buffer-pool-size` (e.g. `16G`) | Hosts that need more (or less) than the 1G default; the stock 128 MB thrashes on multi-GB datasets |
| `XCHAIN_NODE_DB_MAX_CONNECTIONS` | `max-connections` (e.g. `300`) | Many connection pools against one DB (replicas, shared services) |
| `XCHAIN_NODE_DB_FLUSH_LOG_AT_TRX_COMMIT` | `innodb-flush-log-at-trx-commit` (e.g. `2`) | Replica/cache DBs where a 1-second crash window is acceptable for speed |

## Autoheal (restart-on-unhealthy)

Every persistent service container carries a Docker healthcheck, but Docker itself takes no action on the `unhealthy` state (`--restart unless-stopped` only fires when the process exits). An alive-but-stalled service would otherwise stay wedged until an operator notices it in `docker ps`. `xchain-node autoheal` closes that loop: it restarts containers that have been continuously unhealthy past a grace window, for services opted in via `autoheal: true` in the healthcheck table (currently the decoder and indexer; the utxo-tracker is deliberately excluded because it halts on purpose rather than exiting, and a restart would just re-halt it; the encoder is deliberately excluded because its health probe reports utxo-tracker readiness (unreachable, halted, lagging or mempool not ready), which restarting the encoder cannot clear).

The command is one-shot and never prompts or daemonizes. Unattended remediation requires wiring it to a cron entry or systemd timer, e.g. `*/5 * * * * xchain_node autoheal`. Detection-to-restart latency is the timer interval plus the health retry budget plus the grace window. Use `--dry-run` to see restart candidates without acting. Exit code is non-zero only when a restart was attempted and failed.
The command is one-shot and never prompts or daemonizes. Unattended remediation requires wiring it to a cron entry or systemd timer, e.g. `*/5 * * * * xchain_node autoheal`. Detection-to-restart latency is the timer interval plus the health retry budget plus the grace window. Use `--dry-run` to see restart candidates without acting. Exit codes: `1` when a restart was attempted and failed, `2` when a container has been restarted twice this episode without recovering (a wedge restarts are not clearing; investigate), and `0` otherwise. The escalation also logs a warning on stderr, so a systemd `OnFailure=` hook trips on it and cron mails it even when stdout is discarded. It repeats on every pass until the container recovers.

| Variable | Default | What it controls |
|---|---|---|
| `XCHAIN_NODE_AUTOHEAL_GRACE_MS` | `120000` | How long a container must be continuously unhealthy before a restart is considered |
| `XCHAIN_NODE_AUTOHEAL_COOLDOWN_MS` | `600000` | Base wait before autoheal restarts the same container again (anti-flap). The first retry waits this long; each further restart of a container that has not recovered doubles the wait, up to `XCHAIN_NODE_AUTOHEAL_COOLDOWN_CEILING_MS` (with defaults: 10m, 20m, 40m and so on, capped at 6h). The doubling resets once the container recovers |
| `XCHAIN_NODE_AUTOHEAL_COOLDOWN_CEILING_MS` | `21600000` | Upper bound on the doubled cooldown. A container that never recovers settles at one restart per ceiling; there is no attempt cap, and every skipped pass logs an "investigate" line |
| `XCHAIN_NODE_AUTOHEAL_COOLDOWN_CEILING_MS` | `21600000` | Upper bound on the doubled cooldown. A container that never recovers settles at one restart per ceiling; there is no attempt cap, and from the second unrecovered restart on every pass logs an "investigate" warning and exits `2` |
| `XCHAIN_NODE_AUTOHEAL_PROBATION_MS` | `150000` | How long after an autoheal restart a passing health probe counts as that restart's own artifact rather than recovery, so it does not reset the backoff. If you widen a service's start period with `XCHAIN_NODE_HEALTH_START_PERIOD_<SERVICE>`, widen this to match (start period plus interval times retries, plus margin) |
| `XCHAIN_NODE_AUTOHEAL_STATE_DIR` | `~/.xchain-node` | Where the state file (`autoheal-state.json`) lives: last restart times, unhealthy onsets and the per-container restart count that drives the backoff. Falls back to `XCHAIN_NODE_LOCK_DIR` when that is set, otherwise `~/.xchain-node` |

Expand Down
22 changes: 14 additions & 8 deletions bin/pins/at1-suite-titles.json
Original file line number Diff line number Diff line change
Expand Up @@ -772,12 +772,6 @@
"validator stake free-key rules resolves the reuse gate COIN:network first, then the bare network",
"validator stake free-key rules sums amounts exactly in 1e-8 units and refuses to guess on a malformed one"
],
"332b1a20f0f85580": [
"ValidatorService coin wallets the emitted signer marks post-funding failures does not tag a successful two-phase publish",
"ValidatorService coin wallets the emitted signer marks post-funding failures is valid JavaScript once the template literal is expanded",
"ValidatorService coin wallets the emitted signer marks post-funding failures leaves a pre-funding failure untagged, so the round stays retryable",
"ValidatorService coin wallets the emitted signer marks post-funding failures tags a definitive phase-2 rejection with fundsCommitted and the phase-1 txid"
],
"332bea463a49f99c": [
"Regression Suite [regression:p0] Security R-SEC-001: branch name with shell metacharacters rejected",
"Regression Suite [regression:p0] Security R-SEC-002: branch name with backticks and $() rejected",
Expand Down Expand Up @@ -1490,6 +1484,18 @@
"makeBootstrap() consults the source health gate gates the utxo-tracker BEFORE stopping its container, so a refusal costs no downtime",
"makeBootstrap() consults the source health gate still rejects an unsupported module before consulting the gate"
],
"55d86c81bb4903d3": [
"ValidatorService coin wallets the emitted signer builds and signs the reveal before the commit broadcast broadcasts nothing when the encoder refuses the reveal",
"ValidatorService coin wallets the emitted signer builds and signs the reveal before the commit broadcast broadcasts nothing when the reveal cannot be signed",
"ValidatorService coin wallets the emitted signer builds and signs the reveal before the commit broadcast builds no reveal for a single-transaction encoding",
"ValidatorService coin wallets the emitted signer builds and signs the reveal before the commit broadcast builds the reveal from the signed commit, then broadcasts the commit and the reveal",
"ValidatorService coin wallets the emitted signer builds and signs the reveal before the commit broadcast hands back the signed reveal when its broadcast fails after the commit",
"ValidatorService coin wallets the emitted signer builds and signs the reveal before the commit broadcast leaves a commit broadcast failure untagged for the hub to classify",
"ValidatorService coin wallets the emitted signer marks post-funding failures does not tag a successful two-phase publish",
"ValidatorService coin wallets the emitted signer marks post-funding failures is valid JavaScript once the template literal is expanded",
"ValidatorService coin wallets the emitted signer marks post-funding failures marks a pre-funding failure neverSent and not fundsCommitted, so the round stays retryable",
"ValidatorService coin wallets the emitted signer marks post-funding failures tags a definitive phase-2 rejection with fundsCommitted, the phase-1 txid and the signed reveal"
],
"56897dc4174a8788": [
"Chaos: Download Resilience Experiment 8c: SHA-256 hash mismatch succeeds when hash matches exactly",
"Chaos: Download Resilience Experiment 8c: SHA-256 hash mismatch throws with expected vs actual hash on mismatch"
Expand Down Expand Up @@ -5112,7 +5118,7 @@
"test/unit/validator_service.test/11_validator_dir.test.js": "26f27dbd3b14ec37",
"test/unit/validator_service.test/12_coin_wallets.test.js": "6d7114a33630b804",
"test/unit/validator_service.test/13_coin_wallet_options_and_mounts.test.js": "3670f7eb60a0bd6e",
"test/unit/validator_service.test/14_emitted_signer_post_funding_failures.test.js": "332b1a20f0f85580",
"test/unit/validator_service.test/14_emitted_signer_post_funding_failures.test.js": "55d86c81bb4903d3",
"test/unit/validator_service.test/15_hub_env_wiring.test.js": "1dc33a33679f1947",
"test/unit/validator_service.test/16_rollcall_status_reporting.test.js": "cb99d238d302d2c2",
"test/unit/validator_service.test/17_capability_drift_probe.test.js": "1ee619322512f5f5",
Expand Down Expand Up @@ -5536,7 +5542,7 @@
"test/unit/validator_service.test/11_validator_dir.test.js": "26f27dbd3b14ec37",
"test/unit/validator_service.test/12_coin_wallets.test.js": "6d7114a33630b804",
"test/unit/validator_service.test/13_coin_wallet_options_and_mounts.test.js": "3670f7eb60a0bd6e",
"test/unit/validator_service.test/14_emitted_signer_post_funding_failures.test.js": "332b1a20f0f85580",
"test/unit/validator_service.test/14_emitted_signer_post_funding_failures.test.js": "55d86c81bb4903d3",
"test/unit/validator_service.test/15_hub_env_wiring.test.js": "1dc33a33679f1947",
"test/unit/validator_service.test/16_rollcall_status_reporting.test.js": "cb99d238d302d2c2",
"test/unit/validator_service.test/17_capability_drift_probe.test.js": "1ee619322512f5f5",
Expand Down
4 changes: 2 additions & 2 deletions bin/pins/identity.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"repo": "xchain-node",
"vendored": "src/coins (sync-coins.sh)",
"files": {
"src/coins/BTC.js": "182baf5173e3846b94a5edc1ae15913a54fb266addfc45a3cf9a013bd9ec16c6",
"src/coins/DOGE.js": "4659b45fb7a5c959ce2777ab9d5e7c193f3515f03cdd8cd23bb6b9c4d012fc11",
"src/coins/BTC.js": "6868afc2d18911ba112234c980c094fda71cfc3e744a00f493def781c7610f8d",
"src/coins/DOGE.js": "29ac02299b0c779f4e3eda579eeaa9f673c454b73cfe9978a35f03f0e9aed33c",
"src/coins/LTC.js": "6155195bfa5fdfeab77dec3802ce67b5cc47a77695e81a4a5545d980e4c421dd",
"src/coins/consensus_pin.js": "342bf7af224a19ea0a98ff9cfb2c9a70b3fd5be75de7ecef2db05936f82baa63",
"src/coins/index.js": "08b678d934fa647d3c7d14dc5ccdaeb86722ee32a3662de69e4a31cd7b09234c"
Expand Down
Loading
Loading