Production Rust service topology
This document is the deployment authority map for the Rust migration. It is deliberately stricter than the parity inventory: keeping a Node implementation for comparison does not make it a production authority.
Authority matrix
| Plane | Runtime artifact | Deployment status | Fail-closed boundary |
|---|---|---|---|
| Nitro frontier / host | from | Rust authoritative measured EIF | Unimplemented request types return an explicit refusal; there is no Node fallback. NeoX uses the measured for EIP-1559 submission, while NeoX fulfillment proofs use the separate measured for semantic EIP-191 signing. |
| Custody signer | from | Rust authoritative measured EIF | Boots sealed, accepts only the attested provisioning whitelist, and returns 503 until provisioning succeeds. |
| Relayer | from | Rust authoritative production service | Neo N3 and NeoX request/feed lanes require custody signing, successful HALT/receipt confirmation, and durable success before advancing state. , , and are supported. The measured host can execute one already-claimed ; the durable relayer scheduler remains unimplemented and production configuration keeps that lane disabled. |
| Historical worker / relayer | , | Node compatibility only | Not published by the production image workflow, not assigned , and not boot-enabled. Compose requires explicitly pinned images; systemd requires . |
| Historical chain writers | (including ), | Node compatibility only | Every discovered writer/top-up/fulfiller unit — mainnet, testnet, or a future suffix — requires its lane marker, has no , and / both Rust relayer units. The NeoX fulfiller additionally exits 78 whenever . A TestNet Node pusher is the same class of artifact as the mainnet Node pusher: it is not a production writer. |
| Edge feed / automation | Cloudflare control plane | Non-authoritative ingress | returns 410 because Rust owns feed publication; returns 503 without creating a workflow while Rust automation remains fail-closed. Legacy bindings/classes are recovery metadata, not fallback authority. |
The frozen JavaScript parity baseline stays in the repository. It is test input and rollback evidence, not an executable fallback inside a Rust service.
Published images
builds only these service Dockerfiles:The workflow emits immutable
tags only. It emits no branch tag, , legacy alias, Node worker image, or Node relayer image. Nitro operators still rebuild and re-measure the host and signer EIFs with the exact network/custody trust anchors; a registry rootfs tag is not a PCR approval.The frontier measurement binds all six custody identities:
The two NeoX identities are deliberately non-interchangeable: the updater owns EIP-1559 transaction submission, while the verifier owns semantic EIP-191 fulfillment proofs. The build refuses to measure an image if the ids are equal.
Changing any identity requires rebuilding the EIF, recording the new measurement manifest, and updating the KMS/attestation policy as one release.
Host layout
The production host runs the measured frontier and custody EIFs through:
- and its credential-rotation timer
The launch/provision/build scripts use Bash,
, , , and ; they do not require Node. Provisioning projects only allowlisted fields, keeps credentials out of command-line arguments, and leaves existing in-enclave credentials untouched when IMDSv2 rotation fails.The Rust services still consume
as a legacy-named deployment-mode contract: core, compute, and host use it to disable ephemeral keys and unsafe overrides. Its presence in a Rust unit or image is therefore a fail-closed safety input, not a Node runtime dependency. A future migration may replace the name with a Rust-native deployment-mode key only after every consumer has moved atomically. is a constrained host networking sidecar. Its CONNECT allowlist is not a compute, custody, signing, transaction-building, or broadcast authority. Replacing that helper is independent of the service authority cutover and must not broaden the allowlist.The Rust relayer is installed at
. Before enabling its production unit:- Copy to and replace every placeholder.
- Run as the service user.
- Keep ; and refuse the service if the unavailable automation commit protocol is requested. cannot opt in. Non-production may set only as an explicit development allow.
- Enable exactly one of or ; the units conflict to prevent duplicate processing.
- Keep every Node feed writer stopped — including — and remove all markers. Those units have no target, so they cannot be 'd. They / both Rust relayer units as a second line of defense. Rust is the only production writer on mainnet and TestNet.
The relayer transport currently sends a bearer token to custody. Configure a dedicated bearer caller for
; do not substitute a caller, which intentionally has no token and is not yet a relayer authentication transport. Keep that caller distinct from , which authenticates the relayer to the frontier host.The Docker alternative is
. It requires an immutable image and runs the same configuration preflight as its health check. Every other file under is labelled Node compatibility and refuses to resolve without pinned compatibility images.Release gates
Run:
prevents production workflow/systemd/Compose drift
back to Node authority, discovers every Node feed writer under ,
rejects boot-enabled compatibility chain writers on any network suffix,
checks the Cloudflare feed/automation refusals, verifies both NeoX custody
anchors are measured, and keeps automation disabled in the production template.
The request/feed cutover is backed by real custody-to-broadcast, HALT/receipt
confirmation, durable state, restart, and failure-injection tests; changing a
label or image name alone would not have been a cutover.
Feed writer discovery gate
Overview
A hardcoded mainnet unit list is not an authority map. The topology gate walks
for every Node chain-writer / and checks each one. A future file is in scope the moment it lands; omitting TestNet from an allowlist is a failed audit, not a pass.Writer units are names matching
, , or with a or suffix. Freshness monitors and DB prune units are not writers and are not in this set.API Reference
exports:| Symbol | Contract |
|---|---|
| True only for the writer name classes above | |
| Lane marker: , , or | |
| Recursive scan of for writer units | |
| Writer authority, compatibility marker, mutual exclusion, and enable posture | |
| Compatibility-only label, marker, / both Rust relayers, no | |
| Rust relayer every discovered writer basename | |
| Operator docs must not a discovered writer |
Each Node writer must fail closed unless the operator creates the marker and starts (never enables) the unit while both Rust relayers are stopped. CI does not invoke
; the gate is a strict unit-file parse.Usage Examples
Regression fixtures live under
:- — compliant mainnet units plus a boot-enabled TestNet writer. A mainnet-only allowlist would pass; discovery must fail.
- — TestNet units with marker, mutual exclusion, and no . Discovery must pass.
Design decisions
- Rust is the only production writer. Node feed-pusher / top-up / fulfiller units, including TestNet, are disabled compatibility artifacts.
- Discover, do not enumerate. Hardcoding mainnet names produced a false pass while remained enableable.
- Fail closed on enable posture. No section, an explicit path marker, and / both and .
- Docs are in the same gate. An instruction for a discovered writer is an audit failure even if the unit file is correct.
Test Coverage
| Case | Expected |
|---|---|
| Repository audit | returns |
| Discovery includes TestNet | is found under |
| Mainnet-only allowlist | Fixture with a boot-enabled TestNet writer fails only when discovery is used |
| Compliant TestNet unit | Marker + Conflicts/Before + no passes |
| Rust authority vs discovered writers | Missing on a discovered TestNet unit fails |
| Docs enable posture | of a writer stem fails the audit |