@@ -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