@@ -150,7 +150,8 @@ preserved.
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Space-CLI Web UI (gotty terminal) | 8080 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | Basic auth: `admin:<store.password>` |
|
||||
| Explorer Web UI | 3000 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | SvelteKit explorer. **TODO** — daemon stubbed pending the prebuilt explorer image; the interface is still registered but nothing listens yet. |
|
||||
| Subspaces Web UI | 7777 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs` UI. No built-in auth. Only useful while Subspaces is enabled. |
|
||||
| Subspaces Web UI | 7777 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs` daemon (subsd). No built-in auth. Only useful while Subspaces is enabled. |
|
||||
| Subs API | 7777 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | The subsd REST API (same daemon/port as above), exposed as a distinct `api` interface separate from the prover and registry. Only useful while Subspaces is enabled. |
|
||||
| Subspaces Prover | 8888 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs-prover` RISC Zero prover server (no GPU). Its own StartOS interface. Only useful while Subspaces is enabled. |
|
||||
| Subspaces Registry | 8081 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `registry-server` for publishing/resolving handles (remapped from its upstream default 8080 to avoid colliding with the gotty terminal on 8080). Its own StartOS interface. Only useful while Subspaces is enabled. |
|
||||
| Certrelay | 7778 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `certrelay` server (always on). Serves cryptographic proofs binding handles to owner keys. **Setup:** run **Configure Certrelay** and set `CERTRELAY_SELF_URL` to the publicly visible URL StartOS exposes for this interface. |
|
||||
@@ -178,6 +179,7 @@ preserved.
|
||||
| `enable-subspaces` | Enable Subspaces | Enabled (hidden when already on) | Any | Sets `store.enableSubspaces = true` and triggers a service restart so the Subspaces chain (build → wallet → subs-prover → subs) takes effect. |
|
||||
| `disable-subspaces` | Disable Subspaces | Enabled (hidden when already off) | Any | Sets `store.enableSubspaces = false` and triggers a service restart so the subs and subs-prover daemons stop. On-disk data at `/data/subspaces` is preserved. |
|
||||
| `reset-subspaces-state` | Reset Subspaces State | Enabled | Any | Deletes `/data/subspaces` (runtime data only — binaries ship in the image). Use to wipe local handles/proofs. The spaces wallet on spaced is preserved. Warning-gated. |
|
||||
| `set-subs-prover` | Enable / Disable Subspaces Prover | Enabled | Any | Toggle (`store.enableSubsProver`, default **off**) that starts/stops only the `subs-prover` daemon, independent of the overall Subspaces toggle. When off, the daemon doesn't start but its interface (8888) stays registered. Saving restarts the service. |
|
||||
| `configure-certrelay` | Configure Certrelay | Enabled | Any | Sets `CERTRELAY_SELF_URL` (text), `CERTRELAY_BOOTSTRAP` (toggle), and `CERTRELAY_HEALTHCHECK_HANDLE` (text) in `store.json`; prefilled with current values. Saving restarts the service so certrelay picks up the new config. |
|
||||
|
||||
## Backups and Restore
|
||||
@@ -193,7 +195,7 @@ the same idempotent init logic runs and reuses the existing credentials in
|
||||
| --- | --- | --- | --- |
|
||||
| `postgres` (daemon `ready`) | Database | 60 s | TCP listen on `127.0.0.1:5432` |
|
||||
| `spaced` (daemon `ready`) | Spaced RPC | 120 s | TCP listen on `127.0.0.1:7225` |
|
||||
| `subs-prover` (daemon `ready`) | Subspaces Prover | 60 s | TCP listen on `0.0.0.0:8888`. Only present when Subspaces is enabled. |
|
||||
| `subs-prover` (daemon `ready`) | Subspaces Prover | 60 s | TCP listen on `0.0.0.0:8888`. Only present when Subspaces **and** the `set-subs-prover` toggle are enabled (toggle defaults off). Polled every 30 s; nothing depends on it. |
|
||||
| `subs-registry` (daemon `ready`) | Subspaces Registry | 60 s | TCP listen on `0.0.0.0:8081`. Only present when Subspaces is enabled. |
|
||||
| `subs` (daemon `ready`) | Subspaces Web UI | 60 s | TCP listen on `0.0.0.0:7777`. Only present when Subspaces is enabled. |
|
||||
| `certrelay` (daemon `ready`) | Certrelay | 120 s | TCP listen on `0.0.0.0:7778`. Always on. Polled every 30 s. |
|
||||
@@ -240,8 +242,11 @@ the same idempotent init logic runs and reuses the existing credentials in
|
||||
Subspaces** to start it. It ships as the prebuilt `horologger/subs:v0.1.0`
|
||||
image (no compile step), so enabling is fast — the three daemons start as
|
||||
soon as the image is on the box. Enabling runs three daemons, each with its
|
||||
own StartOS interface: **subs** (Web UI, 7777), **subs-prover** (8888, no
|
||||
GPU), **registry-server** (8081). subs loads the existing `default` spaces
|
||||
own StartOS interface: **subs** (Web UI, 7777), **registry-server** (8081),
|
||||
and — only if the separate **Enable / Disable Subspaces Prover** toggle is
|
||||
on (default **off**) — **subs-prover** (8888, no GPU). The prover's
|
||||
interface is always registered even when its daemon is off. subs loads the
|
||||
existing `default` spaces
|
||||
wallet at startup and does **not** create it — create it first from the
|
||||
Space-CLI Web UI with `spaces createwallet` if you haven't. Subspaces is
|
||||
independent of the Embedded Explorer toggle — you can run any combination
|
||||
@@ -348,6 +353,7 @@ explorer_ui:
|
||||
subspaces:
|
||||
default_enabled: false # opt-in via Enable Subspaces action
|
||||
store_field: enableSubspaces
|
||||
subs_prover_default_enabled: false # separate toggle: set-subs-prover (store.enableSubsProver)
|
||||
image: horologger/subs:v0.1.0 # prebuilt; no compile step
|
||||
data_dir: /data/subspaces/data
|
||||
wallet: default # loaded by subs, NOT created (create via space-cli first)
|
||||
@@ -407,6 +413,7 @@ actions:
|
||||
- reset-explorer-state
|
||||
- enable-subspaces
|
||||
- disable-subspaces
|
||||
- set-subs-prover
|
||||
- reset-subspaces-state
|
||||
- configure-certrelay
|
||||
```
|
||||
|
||||
@@ -13,6 +13,7 @@ import { resetPassword } from './resetPassword'
|
||||
import { resetSpacedState } from './resetSpacedState'
|
||||
import { resetSubspacesState } from './resetSubspacesState'
|
||||
import { setBitcoinRpc } from './setBitcoinRpc'
|
||||
import { setSubsProver } from './setSubsProver'
|
||||
import { showCredentials } from './showCredentials'
|
||||
import { showDbCredentials } from './showDbCredentials'
|
||||
import { showPassword } from './showPassword'
|
||||
@@ -35,5 +36,6 @@ export const actions = sdk.Actions.of()
|
||||
.addAction(resetExplorerState)
|
||||
.addAction(enableSubspaces)
|
||||
.addAction(disableSubspaces)
|
||||
.addAction(setSubsProver)
|
||||
.addAction(resetSubspacesState)
|
||||
.addAction(configureCertrelay)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { storeJson } from '../fileModels/storeJson'
|
||||
import { i18n } from '../i18n'
|
||||
import { sdk } from '../sdk'
|
||||
|
||||
const { InputSpec, Value } = sdk
|
||||
|
||||
const inputSpec = InputSpec.of({
|
||||
enabled: Value.toggle({
|
||||
name: i18n('Run Subspaces Prover'),
|
||||
description: i18n(
|
||||
'When on, the subs-prover daemon starts (only while Subspaces itself is enabled). It runs lengthy timing tests on boot and can take a long time to become ready. Off by default. The Subspaces Prover interface (port 8888) stays registered either way.',
|
||||
),
|
||||
warning: null,
|
||||
footnote: null,
|
||||
default: false,
|
||||
}),
|
||||
})
|
||||
|
||||
export const setSubsProver = sdk.Action.withInput(
|
||||
// id
|
||||
'set-subs-prover',
|
||||
|
||||
// metadata
|
||||
async ({ effects }) => ({
|
||||
name: i18n('Enable / Disable Subspaces Prover'),
|
||||
description: i18n(
|
||||
'Independently start or stop the subs-prover daemon, separate from the overall Subspaces toggle. Saving restarts the service.',
|
||||
),
|
||||
warning: null,
|
||||
allowedStatuses: 'any',
|
||||
group: null,
|
||||
visibility: 'enabled',
|
||||
}),
|
||||
|
||||
// input
|
||||
inputSpec,
|
||||
|
||||
// prefill — current value
|
||||
async ({ effects }) => {
|
||||
const enabled = await storeJson.read((s) => s.enableSubsProver).once()
|
||||
return { enabled: enabled === true }
|
||||
},
|
||||
|
||||
// run
|
||||
async ({ effects, input }) => {
|
||||
await storeJson.merge(effects, { enableSubsProver: input.enabled })
|
||||
|
||||
return {
|
||||
version: '1',
|
||||
title: i18n('Success'),
|
||||
message: input.enabled
|
||||
? i18n(
|
||||
'Subspaces Prover enabled. The service is restarting; the prover starts after the other Subspaces daemons and may take a while to become ready.',
|
||||
)
|
||||
: i18n(
|
||||
'Subspaces Prover disabled. The service is restarting; the prover daemon will not start. Its interface (8888) remains registered.',
|
||||
),
|
||||
result: null,
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -27,6 +27,7 @@ const shape = z.object({
|
||||
.catch(null),
|
||||
enableExplorer: z.boolean().nullable().catch(null),
|
||||
enableSubspaces: z.boolean().nullable().catch(null),
|
||||
enableSubsProver: z.boolean().nullable().catch(null),
|
||||
certrelaySelfUrl: z.string().nullable().catch(null),
|
||||
certrelayBootstrap: z.boolean().nullable().catch(null),
|
||||
certrelayHealthcheckHandle: z.string().nullable().catch(null),
|
||||
|
||||
@@ -128,6 +128,19 @@ const dict = {
|
||||
133,
|
||||
'Certrelay configuration saved. The service is restarting to apply the new settings.':
|
||||
134,
|
||||
'Enable / Disable Subspaces Prover': 135,
|
||||
'Independently start or stop the subs-prover daemon, separate from the overall Subspaces toggle. Saving restarts the service.':
|
||||
136,
|
||||
'Run Subspaces Prover': 137,
|
||||
'When on, the subs-prover daemon starts (only while Subspaces itself is enabled). It runs lengthy timing tests on boot and can take a long time to become ready. Off by default. The Subspaces Prover interface (port 8888) stays registered either way.':
|
||||
138,
|
||||
'Subspaces Prover enabled. The service is restarting; the prover starts after the other Subspaces daemons and may take a while to become ready.':
|
||||
139,
|
||||
'Subspaces Prover disabled. The service is restarting; the prover daemon will not start. Its interface (8888) remains registered.':
|
||||
140,
|
||||
'Subs API': 141,
|
||||
'REST API of the subs daemon (subsd) for Subspaces operations. Distinct from the Subspaces Prover and Subspaces Registry. Only useful while Subspaces is enabled.':
|
||||
142,
|
||||
|
||||
// interfaces.ts
|
||||
'Space-CLI Web UI': 12,
|
||||
|
||||
@@ -2,12 +2,16 @@ import { storeJson } from '../fileModels/storeJson'
|
||||
import { sdk } from '../sdk'
|
||||
|
||||
export const taskSeedEnableSubspaces = sdk.setupOnInit(async (effects) => {
|
||||
const existing = await storeJson.read((s) => s.enableSubspaces).once()
|
||||
if (existing !== null && existing !== undefined) return
|
||||
const store = await storeJson.read().once()
|
||||
|
||||
await storeJson.merge(
|
||||
effects,
|
||||
{ enableSubspaces: false },
|
||||
{ allowWriteAfterConst: true },
|
||||
)
|
||||
const patch: { enableSubspaces?: boolean; enableSubsProver?: boolean } = {}
|
||||
if (store?.enableSubspaces === null || store?.enableSubspaces === undefined)
|
||||
patch.enableSubspaces = false
|
||||
// subs-prover is independently gated and defaults OFF.
|
||||
if (store?.enableSubsProver === null || store?.enableSubsProver === undefined)
|
||||
patch.enableSubsProver = false
|
||||
|
||||
if (Object.keys(patch).length > 0) {
|
||||
await storeJson.merge(effects, patch, { allowWriteAfterConst: true })
|
||||
}
|
||||
})
|
||||
|
||||
+21
-1
@@ -68,7 +68,27 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
||||
query: {},
|
||||
})
|
||||
|
||||
const subspacesReceipt = await subspacesMultiOrigin.export([subspaces])
|
||||
// The subs daemon ("subsd — HTTP REST API server for subs operations") serves
|
||||
// its REST API on the same port. Expose it as a distinct `api` interface,
|
||||
// separate from the prover (8888) and registry (8081) interfaces.
|
||||
const subsApi = sdk.createInterface(effects, {
|
||||
name: i18n('Subs API'),
|
||||
id: 'subs-api',
|
||||
description: i18n(
|
||||
'REST API of the subs daemon (subsd) for Subspaces operations. Distinct from the Subspaces Prover and Subspaces Registry. Only useful while Subspaces is enabled.',
|
||||
),
|
||||
type: 'api',
|
||||
masked: false,
|
||||
schemeOverride: null,
|
||||
username: null,
|
||||
path: '',
|
||||
query: {},
|
||||
})
|
||||
|
||||
const subspacesReceipt = await subspacesMultiOrigin.export([
|
||||
subspaces,
|
||||
subsApi,
|
||||
])
|
||||
|
||||
const proverMulti = sdk.MultiHost.of(effects, 'subspaces-prover-multi')
|
||||
const proverMultiOrigin = await proverMulti.bindPort(SUBSPACES_PROVER_PORT, {
|
||||
|
||||
+42
-28
@@ -56,6 +56,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
||||
const { password: APP_PASSWORD, btcAuth, dbAuth, spacedAuth } = store
|
||||
const enableExplorer = store.enableExplorer === true
|
||||
const enableSubspaces = store.enableSubspaces === true
|
||||
// subs-prover is independently gated and defaults OFF (null/undefined => false).
|
||||
const enableSubsProver = store.enableSubsProver === true
|
||||
|
||||
const spacedEnv = {
|
||||
SPACED_CHAIN,
|
||||
@@ -262,8 +264,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
||||
// Appends the Subspaces chain (fetch → build → wallet ensure → subs-prover →
|
||||
// subs daemon) to any existing chain. `as any` because the chain's TS type
|
||||
// depends on prior IDs and we can't easily express the union here.
|
||||
const withSubspaces = (chain: any): any =>
|
||||
chain
|
||||
const withSubspaces = (chain: any): any => {
|
||||
let c = chain
|
||||
.addOneshot('subspaces-dirs', {
|
||||
subcontainer: subspacesSub,
|
||||
exec: {
|
||||
@@ -278,32 +280,6 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
||||
},
|
||||
requires: [],
|
||||
})
|
||||
.addDaemon('subs-prover', {
|
||||
subcontainer: subspacesSub,
|
||||
exec: {
|
||||
command: [
|
||||
'sh',
|
||||
'-c',
|
||||
`cd ${SUBSPACES_PROVER_DIR} && exec ${SUBSPACES_PROVER_BIN} --server --server-port ${SUBSPACES_PROVER_PORT}`,
|
||||
],
|
||||
env: proverEnv,
|
||||
// Run as root: the horologger/subs image declares USER subs, but our
|
||||
// /data volume + subdirs are root-owned, so the non-root user can't
|
||||
// traverse/write them. Root sidesteps the ownership mismatch.
|
||||
user: 'root',
|
||||
},
|
||||
ready: {
|
||||
display: i18n('Subspaces Prover'),
|
||||
fn: () =>
|
||||
sdk.healthCheck.checkPortListening(effects, SUBSPACES_PROVER_PORT, {
|
||||
successMessage: i18n('subs-prover is ready'),
|
||||
errorMessage: i18n('subs-prover is not ready'),
|
||||
}),
|
||||
gracePeriod: 60_000,
|
||||
trigger: sdk.trigger.cooldownTrigger(30_000),
|
||||
},
|
||||
requires: ['subspaces-dirs'],
|
||||
})
|
||||
.addDaemon('subs-registry', {
|
||||
subcontainer: subspacesSub,
|
||||
exec: {
|
||||
@@ -349,6 +325,44 @@ export const main = sdk.setupMain(async ({ effects }) => {
|
||||
requires: ['subspaces-dirs', 'spaced', 'subs-registry'],
|
||||
})
|
||||
|
||||
// subs-prover is opt-in and DISABLED BY DEFAULT (toggle via the "Enable
|
||||
// Subspaces Prover" action). Its interface (8888) stays registered either
|
||||
// way (see interfaces.ts), but the daemon only starts when enabled. It's
|
||||
// added LAST and depends on every other subspaces daemon; it runs lengthy
|
||||
// timing tests on boot and NOTHING depends on it, so its slow startup never
|
||||
// blocks anything else.
|
||||
if (enableSubsProver) {
|
||||
c = c.addDaemon('subs-prover', {
|
||||
subcontainer: subspacesSub,
|
||||
exec: {
|
||||
command: [
|
||||
'sh',
|
||||
'-c',
|
||||
`cd ${SUBSPACES_PROVER_DIR} && exec ${SUBSPACES_PROVER_BIN} --server --server-port ${SUBSPACES_PROVER_PORT}`,
|
||||
],
|
||||
env: proverEnv,
|
||||
// Run as root: the horologger/subs image declares USER subs, but our
|
||||
// /data volume + subdirs are root-owned, so the non-root user can't
|
||||
// traverse/write them. Root sidesteps the ownership mismatch.
|
||||
user: 'root',
|
||||
},
|
||||
ready: {
|
||||
display: i18n('Subspaces Prover'),
|
||||
fn: () =>
|
||||
sdk.healthCheck.checkPortListening(effects, SUBSPACES_PROVER_PORT, {
|
||||
successMessage: i18n('subs-prover is ready'),
|
||||
errorMessage: i18n('subs-prover is not ready'),
|
||||
}),
|
||||
gracePeriod: 60_000,
|
||||
trigger: sdk.trigger.cooldownTrigger(30_000),
|
||||
},
|
||||
requires: ['subspaces-dirs', 'subs-registry', 'subs'],
|
||||
})
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
if (!enableExplorer) {
|
||||
// Spaces-only mode: spaced + gotty terminal. No PostgreSQL, no indexer.
|
||||
// User can flip the toggle via the Enable Embedded Explorer action;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { VersionGraph } from '@start9labs/start-sdk'
|
||||
import { v_0_0_9_1 } from './v0.0.9.1'
|
||||
import { v_0_0_9_2 } from './v0.0.9.2'
|
||||
|
||||
export const versionGraph = VersionGraph.of({
|
||||
current: v_0_0_9_1,
|
||||
current: v_0_0_9_2,
|
||||
other: [],
|
||||
})
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
|
||||
|
||||
export const v_0_0_9_1 = VersionInfo.of({
|
||||
version: '0.0.9:1',
|
||||
export const v_0_0_9_2 = VersionInfo.of({
|
||||
version: '0.0.9:2',
|
||||
releaseNotes: {
|
||||
en_US: `- Embedded Certrelay (prebuilt \`horologger/certrelay:v0.2.3\` image, static musl binaries). Always on — runs the \`certrelay\` server on port 7778 from service start, as its own StartOS interface. It serves cryptographic proofs binding Bitcoin-anchored handles to owner keys, talking to the local spaced over loopback using the store.spacedAuth credentials. The bundled \`fabric\` CLI is copied to /data/bin/fabric so it's runnable from the Space-CLI Web UI. New "Configure Certrelay" action sets CERTRELAY_SELF_URL, CERTRELAY_BOOTSTRAP, and CERTRELAY_HEALTHCHECK_HANDLE (stored in store.json; saving restarts the service). Set CERTRELAY_SELF_URL to the publicly visible URL StartOS exposes for the Certrelay interface.
|
||||
en_US: `- Added a dedicated "Subs API" interface (type api) on the subs daemon's port (7777), distinct from the Subspaces Prover (8888) and Subspaces Registry (8081) interfaces. The subs daemon is "subsd — an HTTP REST API server"; this surfaces that REST API as its own dashboard entry.
|
||||
- New "Enable / Disable Subspaces Prover" action independently gates just the subs-prover daemon (store.enableSubsProver), **disabled by default**. When off, subs-prover does not start (it runs lengthy boot-time timing tests), but its interface on 8888 stays registered. It is added last and nothing depends on it, so its slow startup never blocks subs, the registry, or certrelay.
|
||||
- Embedded Certrelay (prebuilt \`horologger/certrelay:v0.2.3\` image, static musl binaries). Always on — runs the \`certrelay\` server on port 7778 from service start, as its own StartOS interface. It serves cryptographic proofs binding Bitcoin-anchored handles to owner keys, talking to the local spaced over loopback using the store.spacedAuth credentials. The bundled \`fabric\` CLI is copied to /data/bin/fabric so it's runnable from the Space-CLI Web UI. New "Configure Certrelay" action sets CERTRELAY_SELF_URL, CERTRELAY_BOOTSTRAP, and CERTRELAY_HEALTHCHECK_HANDLE (stored in store.json; saving restarts the service). Set CERTRELAY_SELF_URL to the publicly visible URL StartOS exposes for the Certrelay interface.
|
||||
- Removed the build-from-source chains for the Go indexer and the SvelteKit explorer, and dropped their builder images (\`golang:1.23-alpine\`, \`node:20-alpine\`). This shrinks the .s9pk and removes the multi-minute first-enable compile. The indexer + explorer-UI daemons are now stubbed with TODOs in startos/main.ts pending prebuilt images (indexer image not yet produced; explorer image to be provided). Enabling the embedded explorer currently starts PostgreSQL only. All explorer-indexer actions (show-db-credentials, reset-db-state, reset-indexer-state, reset-explorer-state) are retained.
|
||||
- Embedded Subspaces support (prebuilt \`horologger/subs:v0.1.0\` image). Opt-in via the new "Enable Subspaces" action; "Disable Subspaces" stops it. No compile step — enabling starts three prebuilt daemons, each on its own StartOS interface: **subs** (Web UI, 7777), **subs-prover** (RISC Zero prover, no GPU, 8888), and **registry-server** (handle registry, 8081). subs loads the existing \`default\` spaces wallet at startup (it does not create one). Runtime data persists at /data/subspaces/data across restarts and toggles. New "Reset Subspaces State" action wipes local data. Adds a fifth manifest image (\`horologger/subs:v0.1.0\`, ~84 MB) — switched from building \`spacesops/subs\` from source with \`rust:1-slim\` to shrink the .s9pk and eliminate the multi-minute first-enable compile.
|
||||
- Five distinct interfaces now appear in the dashboard: **Space-CLI Web UI** (gotty terminal, 8080), **Explorer Web UI** (3000, opt-in), **Subspaces Web UI** (7777, opt-in), **Subspaces Prover** (8888, opt-in), **Subspaces Registry** (8081, opt-in). Internal "Web UI" references renamed to **Space-CLI Web UI** for clarity.
|
||||
Reference in New Issue
Block a user