2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00
2026-09-29 15:57:21 +03:00

Validations Proxy

An active-active WebSocket relay for the XAHAUD validations stream. It maintains connections to one or more XAHAUD nodes and broadcasts each unique validationReceived message to downstream clients. Validation versions are the only persisted data.

Validation messages are forwarded byte-for-byte as text frames. The proxy does not add, remove, rename, or resolve fields, so consumers receive XAHAUD's original master_key, server_version, flag-ledger fields, and any fields added by future XAHAUD versions.

The root HTTP page is a live validation dashboard. It shows validator master keys, manifest domains, activity, ledgers, the next 256-ledger flag boundary, and decoded XAHAUD versions. Validators published by vl.xahau.org appear first. The activity table defaults to base-domain ordering, so a host such as validator.example.org sorts under example.org; the full hostname is used as a tie-breaker. Browser data is memory-only and disappears when the page closes. Validator versions are persisted atomically to data/validator-versions.json inside the project directory; validations, domains, activity, and validator-list data are not persisted. Relative VERSION_STORE_PATH values are always resolved inside the project directory. The dashboard defaults to a restrained light theme with an optional non-persistent dark mode.

The dashboard and WebSocket share the same root path: an ordinary HTTP request receives the page, while a WebSocket upgrade receives the live stream. TLS is normally terminated by a reverse proxy.

WebSocket streams

  • ws://localhost:8080/ forwards XAHAUD validationReceived messages unchanged. Use the same root path on your deployment's public wss:// address. There is no replay.
  • ws://localhost:8080/?dashboard=1 sends the same validation stream plus validatorMetadata messages used by the sample dashboard. Use the same query parameter on your deployment's public wss:// address. A metadata frame identifies the validator with master_key and may contain its manifest domain, listed status from vl.xahau.org, explicit offline status, last known encoded server_version, latest ledger_index, relay-observed last_seen time, and monitoring_since timestamp.

When a dashboard connection opens, the relay immediately sends every metadata record it currently knows. Persisted versions can therefore appear before a new validation from that validator. A previously unknown domain is sent after the validator is first observed and the relay resolves its manifest. Listing status is based on the relay's periodically refreshed vl.xahau.org list and is sent again when that status changes. Version metadata is sent when a validation announces server_version; XAHAUD normally includes this on flag-ledger validations rather than every validation.

Every validator in the current VL is represented in dashboard metadata even when it has not sent a validation. The relay immediately sets offline: true for a listed validator that has never been observed. An observed validator is marked offline after falling two ledgers behind the leading ledger, with a 15-second timeout used until ledger activity is available. The relay broadcasts another validatorMetadata frame whenever this status changes; the browser only renders the server-provided status. Availability state is held in memory; only versions are persisted.

The metadata is public enrichment rather than part of XAHAUD's validation message format. Consumers that require the original stream should use the root endpoint. Consumers must tolerate duplicate validations around relay restarts and fields added by future XAHAUD releases.

When multiple upstreams deliver the same signed validation, the first original message is forwarded and subsequent copies are dropped. Deduplication uses the signed data field and a five-minute in-memory cache by default. This cache is empty after a restart, so consumers should still tolerate occasional duplicates.

Run

Requires Node.js 20 or newer.

npm install
cp .env.example .env
set -a; . ./.env; set +a
npm start

Set XAHAUD_WS_URLS to a comma-separated list of XAHAUD node endpoints. You can collect validations from the public wss://xahau.network endpoint, a local node, or multiple nodes for redundancy. For example:

XAHAUD_WS_URLS=wss://xahau.network,ws://127.0.0.1:6008

The relay remains ready while at least one node is connected. To prevent arbitrary clients from using the relay, set DOWNSTREAM_AUTH_TOKEN to a strong secret. Browser deployments should also set ALLOWED_ORIGINS.

Connect a consumer to ws://localhost:8080/ with an authorization header:

import WebSocket from 'ws';

const socket = new WebSocket('ws://localhost:8080/', {
  headers: { Authorization: `Bearer ${process.env.VALIDATIONS_TOKEN}` },
});

socket.on('message', (data) => console.log(JSON.parse(data)));

Web browsers cannot set an Authorization header in the native WebSocket API. For browser consumers, put the relay behind an authenticating reverse proxy that injects the header, or use a cookie-aware gateway.

Endpoints

  • GET / — live validation dashboard
  • GET /healthz — process liveness
  • GET /readyz — returns 200 while at least one XAHAUD node is connected
  • GET /status — per-node connection state plus relay and deduplication counters
  • WS / — live validation messages only; no replay
  • WS /?dashboard=1 — live validations plus public validator metadata

The proxy automatically reconnects to XAHAUD with exponential backoff and jitter. Slow downstream clients are disconnected instead of allowing unbounded memory growth.

Test

npm test

Docker

docker build -t validations-proxy .
docker run --rm -p 8080:8080 \
  -e XAHAUD_WS_URLS=ws://host.docker.internal:6008,ws://xahaud-standby:6008 \
  -e DOWNSTREAM_AUTH_TOKEN=replace-me \
  validations-proxy
Description
No description provided
Readme 51 KiB
Languages
JavaScript 51.7%
HTML 47.7%
Dockerfile 0.6%