Skip to content

Release v0.16.0 - xchain-node - #39

Merged
jdogresorg merged 15 commits into
masterfrom
release/v0.16.0
Sep 8, 2026
Merged

jdogresorg merged 15 commits into
masterfrom
release/v0.16.0

Conversation

@jdogresorg

Copy link
Copy Markdown
Contributor

XChain Platform v0.16.0 release train: this repository's frozen release/v0.16.0 branch, carrying every develop commit since its last tag plus the version bump, CHANGELOG block and README refresh.

A minor train. Two consensus rails arm on Bitcoin testnet by height, both ahead of the chain at cut time: zero-confirmation ATTEST service from block 151800 and ROLLCALL v1 consensus gates from block 152208. Mainnet is unratified and byte for byte unchanged. Testnet indexers roll before hubs, the whole fleet inside one roll-call epoch.

Merge order per the release runbook (section 6, 5b): hub, then decoder/sync/encoder/utxo-tracker, then indexer, then explorer, e2e-test and sdk, node last with the pinned manifest. Merge commit, never squash: the train tag is cut on the merge commit.

…to the latest release

A no-ref `update` on a release node resolves the latest published release and
pins every service to it, the same way a no-ref `install` does; a branch node
stays on its branch and says so. Before this the no-ref path re-read each
module's git branch, and a pinned checkout is detached, so every release node
failed its own documented upgrade command with "branch 'HEAD' not found".

- The node records what it is on (data/install-target.json) at every install
  and update; a node with no record is classified from its checkouts.
- `update all` includes the hub and the sync client, hub first; absent
  services skip and report on one line; an absent coin node is not installed;
  a coin node already at the pinned daemon version is left running.
- The CLI moves itself first: fetch tags, verify the target tag against the
  shipped release key, checkout, npm install (rolled back on failure), then
  re-execute the command in the explicit pinned form. A dirty tracked tree is
  refused with the files named; XCHAIN_NODE_NO_SELF_UPDATE=1 updates the
  services only.
- Every command except `update` prints a one-line notice when a newer release
  exists, cached for an hour, silent on failure.
- On a validator the additive `validator init` repair runs before the hub
  rebuild.
- preCheck stages the hub from the release manifest: a no-ref install pins it
  to the latest release instead of cloning master, and `install v0.15.1
  xchain-hub` works on a train in which the hub did not move.
- `update` no longer requires a service argument.

Driven in a docker-in-docker sandbox: a hub-only stack at the v0.15.1 pin moved
to hub 0.15.2 with a bare `update all`; a 0.15.1 carrier self-updated, re-ran
the pinned update and rebuilt the hub.
…gate can see it

The two reads of the self-update re-execution marker in the CLI used a computed
key, which the documentation coverage scanner cannot match. Read by name; the
variable and the opt-out are documented in the companion documentation change.
feat(update): `update all` moves the CLI and every installed service to the latest release
…honours a clear

A decoder carrying a durable REORG_HALT marker keeps parsing with a green
healthcheck, so `ps` showed a clean "running" for a service that will stop at
its next reorg, and the only recovery anywhere was a full resync.

`clear-reorg-halt <chain> <network> --reason <text> [--force] [--dry-run]` runs
the decoder's own audited clear inside its container (the decoder checks the
database is intact and records the reason as an events row). `ps` probes running
decoders' health surface, marks a live halt as "running REORG_HALT" and prints a
note under the table with the reason, the date and both recoveries. The
bootstrap health gate counts only halts newer than the newest clear, so a
cleared database can be published again.
Nothing ever passed --memory, so every tracker's memoryBudget read the whole
host (its cgroup branch never bound) and N trackers on one box oversubscribed
it: three trackers on a 16 GB host intended 13.7 GB before the chain daemons and
MariaDB, and the mainnet one reached 5.9 GB RSS (operator report 2026-09-07).

The orchestrator is the one thing that knows how many trackers share a host, so
it hands each one its share: half the host RAM divided by the installed tracker
count (registry rows plus the one being created), floor 1024 MB, ceiling
16384 MB, --memory-swap equal to --memory. Only the tracker is capped by
default; it is the one service that sizes itself to the cgroup limit, and a cap
on a service that does not turns a spike into an OOM restart loop. Any module
takes an explicit XCHAIN_NODE_MODULE_MEMORY_MB_<SERVICE>; 0 disables the derived
cap. The limit is fixed at create time, so adding a chain needs a tracker
recreate to re-size the others; the deployment guide says so.
Both run a complete singleton installModule and take 1.2-1.5s on a CI runner
(measured at two consecutive commits), which only fits the 2s default while
the runner is idle; three concurrent gate runs pushed them over and blocked an
unrelated push. The describe blocks now carry a 10s budget.
full_node is a possession-proof tier, not an opt-in capability, and it ships
inert on every network (reward share zero, no verifier set) until its
activation flag day. The capabilities line never listed it, so an operator
whose stake cleared its floor went looking for how to earn it (operator
report 2026-09-07). Status now says so in one line.
…e restoring

A fresh mainnet install restored the published decoder bootstrap next to a
coin node still syncing from zero; the released decoder read the node's lower
tip as a reorg and wrote a durable halt. Both numbers exist at restore time
and nothing compared them.

The publisher now writes bootstrap.json {format, module, coin, network,
height, created} as the FIRST member of the wrapper (decoder/indexer height
from MAX(block_index) after the dump, tracker height from its status before
the stop), and a streaming reader pulls it off the leading tar entry without a
pass over the archive. Between download and restore the install reads the
coin node's getblockchaininfo through its container CLI and decides: at or
past the archive, restore; below it and the service waits out a catching-up
node (its status carries node_catching_up, or its version is 0.16.0+), restore
and report WAITING FOR NODE; below it and the image would halt, refuse, leave
the store untouched and say how to take the restore later. The indexer follows
the decoder and always passes. XCHAIN_NODE_SKIP_NODE_TIP_GUARD=1 skips it
loudly.

`ps` probes decoder and tracker health and marks a service waiting out its
node as WAITING FOR NODE, with both heights under the table.
Pin the nine moved components at their v0.16.0 tags (hub 8ba9b3b, indexer dc864aef, sync 6032d2c, decoder c3b2e8c, encoder c621917, utxo-tracker 1e5ac07, explorer e916639, sdk 7d1634f, e2e-test 685c346); vm, contracts and regtest-miner stay at v0.15.0 (sparse lockstep).
@jdogresorg
jdogresorg merged commit 68bd40e into master Sep 8, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant