Back to list

Development Update — July 20

Two threads ran through today. One was operational safety: updating a visor over its own dmsgpty had been quietly dangerous, because autoconfig ends by restarting the service — which kills the pty session and the in-flight update along with it — so a --no-restart flag now lets the restart happen out-of-band as the last step. The other was closing config gaps: a v1.3.85 regression had silently emptied every visor’s country code, the skycoin-web wallet gained a serve toggle and a full capability-gated custody model, and an audit of the skywire.conf template turned up eight documented-nowhere knobs plus a hypervisor address filed under the wrong heading. In the skycoin monorepo the wallet’s status bar learned the node’s chain identity and its node settings escaped the wizard guard, and the SkyDEX exchange engine moved in — domain logic in skycoin, skywire wrapping only the transport.

Skywire: Pty-Safe Updates

3520 feat(autoconfig): –no-restart flag for pty-safe updates fixes a real failure mode operators had hit in practice. skywire autoconfig ends by restarting skywire.service, and when the operator is updating over the visor’s own dmsgpty, that restart tears down the pty session — and the in-flight apt/autoconfig process with it — leaving the reconfigure half-applied. The install-command generator already had a pty-safe mode for the package install, running it as a systemd-owned install-skywire.service decoupled from the session, but if the operator selected any config option the generated command still ran skywire autoconfig <flags> directly afterward and killed the pty mid-reconfigure. The new --no-restart flag generates and writes the config exactly as before but skips the service restart, so the operator can trigger it out-of-band with systemctl start --no-block skywire-autoconfig.service — a Type=oneshot unit that, because it’s owned by systemd rather than the pty, survives restarting skywire.service from inside it and runs to completion. The flag lives in the shared autoconfigcmd factory so it appears in both the CLI and the WASM install-command generator automatically, and it’s behavior-only — deliberately not written to skywire.conf, with a matching exemption added to the EnvMap-coverage test so the invariant stays honest.

Skywire: A Location Regression

3521 fix(geoip): OpenEmbedded must trigger the lazy decompress (v1.3.85 location regression) restores the country code that every v1.3.85 visor had silently lost from the hypervisor node list — v1.3.84 visors still showed it, and the gap was reported from the field. #3500 had gzipped the embedded GeoLite2-City database and made it decompress lazily inside EmbeddedDB()’s sync.Once, but OpenEmbedded() kept reading the bare embedded package var, which after #3500 is populated only as a side effect of EmbeddedDB() having run first. Since the visor’s own self-geoip lookup is the first geoip call in the process, embedded was still nil, OpenBytes(nil) opened no database, and the visor reported an empty CountryCode. The fix is one line — route OpenEmbedded() through EmbeddedDB() so the decompress is guaranteed to have happened. The existing TestOpenEmbedded had passed only because TestEmbeddedDB ran earlier in the same process and primed the Once; a new TestOpenEmbedded_FirstCall resets the state so OpenEmbedded() is genuinely the first call — the cold path a fresh visor actually hits — and it was verified to fail on the old code and pass on the fix.

Skywire: The Wallet Custody Model

3524 feat(hv): hv serve --wallet to gate serving the skycoin-web wallet adds the outermost toggle: until now the bundled wallet was mounted at /wallet/ unconditionally whenever embedded, and --wallet=false now serves a wallet-less PWA. Custody stays browser-side in that served-PWA context — a served PWA has no per-visor filesystem identity, so the design clamps hv serve to browser custody — making this purely a frontend-serve switch where the host never sees keys either way. Underneath it, 3519 feat(wallet): capability-gated wallet config block (Stage 1) introduces the model the toggle sits on. The wallet frontend is always a browser SPA; the one axis an operator actually chooses is custody — where keys live — across browser (default, keys in localStorage or OPFS, available everywhere), disk (real files at wallet.dir, native and hv serve only), and remote (another visor’s skycoin-web over dmsg). The key idea is capability gating: walletCustodyDiskCapable is a build-tagged constant, true where there’s a filesystem and false under wasm, and WalletCustody() clamps against it — so a config written on a native visor with custody:"disk" still loads under wasm and degrades to browser instead of failing or offering a mode that can’t work. The accessors are nil-safe and opt-out, so a config predating the block serves the wallet with today’s browser behavior, and an unrecognized custody string falls back to browser rather than bricking the wallet on a typo. 3525 feat(wallet): storage section (browser | disk | remote) in the config panel renders that gating in the UI: the /wallet/config panel’s two modes become three — Browser, This host (disk), Remote — with disk hidden unless the embedder signals ?disk=1, which only a native visor with a filesystem and skycoin-web backend sends. Disk mode shows a seed-wallet-store dir field — one directory holding many seed files, not per-coin, since a bip44 seed spans chains — and a prominent trust-model warning that disk means the host holds your keys. Because WalletConfigHTML is a Go string served by both the native HV and wasm hv serve, no wasm re-embed was needed.

Skywire: Documenting the Missing Knobs

3523 fix(cli): document config knobs missing from the skywire.conf template closes a discoverability gap in the /etc/skywire.conf template that config gen -q prints. The hypervisor web-UI address HVHTTPADDR had been filed under “Advanced Tuning” rather than the “Hypervisor UI” section where an operator setting the hypervisor’s LAN ip:port would look — the reported gap — and auditing every SKYENV var that config gen and autoconfig actually read against what the template documented surfaced eight more knobs with no line in the template at all. Those included ENABLEPKENDPOINT for the unauthenticated GET /api/pk, the DMSGWEB/DMSGWEBUPSTREAM and SKYNETWEB/SKYNETWEBUPSTREAM bridges, SKYMAILBRIDGE, and the SKYCOIND_INSTANCES/SKYCOIND_FLAGS daemon controls — all working flags an operator editing the .conf couldn’t discover. All eight were added with descriptions and HVHTTPADDR moved into the Hypervisor UI section with a note distinguishing ':8000' (all interfaces, LAN-reachable) from '127.0.0.1:8000' (local-only); it’s template text only, with no behavior change.

Skycoin: Node Identity in the Status Bar

2940 feat(wallet): node identity in status bar + reachable node settings during onboarding closes two gaps found while configuring the wallet backend in the wasm visor. NodeHealthService keeps the identity fields /api/v1/health already returns but had discarded — coin ticker, blockchain_pubkey (the block-publisher PK that signs the chain, the canonical fiber-coin identity), head hash, version — and probes the effective bitcoin electrum URL from customNodeUrls[btc] instead of a hardcoded path, so health and the wallet’s own balance/history calls point at the same server; the status bar then renders Skycoin (SKY) · block 195,263 · 0328c5…6456a with a full-detail hover tooltip, and the whole strip links to Settings → Node. The second fix ungates node settings behind a dedicated settings/node route outside WizardGuardService: with the old wizard guard an unreachable default node deadlocked you — you couldn’t create a wallet (no node) or change the node (no wallet) — and choosing a working node is inherently a pre-wallet concern. Bitcoin’s “node” is treated as its ssl:// electrum server (defaulting to a public one so BTC works out of the box, with the change-node dialog verifying it via /v1/btc/health tip height rather than the skycoin /api/v1/health). It’s paired with a Skywire-side change that reads the BTC electrum server from the request origin and slims the visor’s outer config panel to transport-only.

Skycoin: The SkyDEX Exchange Engine

2950 SkyDEX exchange engine (skycoin-web-style: domain here, skywire wraps transport) migrates the decentralized-exchange engine into skycoin under src/skydex/* and cmd/skydex-{market,client}, following the same split as skycoin-web: the exchange domain logic and UI live in skycoin with no skywire import, and skywire supplies only the network transport. The engine is transport-agnostic domain logic — every package (db/chain/jobs/walletaddr/protocol plus the server and client cores) has zero skywire dependency, and chain already imports skycoin/src/cipher, coin, transaction directly — so putting the matching/escrow/settlement, SQLite, block-explorer and coin-signing engine in the networking repo was a lot of surface for skywire to carry. The seam is narrow: the market side is server.Accept(ctx, net.Listener, IdentifyFunc) with a 3-method Host (Log / PublishOTP / PubKey) so the operator UI runs standalone or visor-backed, the client dials via MarketDialer.Dial(ref), and cmd/skydex-market / -client are standalone TCP reference builds that make the exchange testable without skywire at all — over skywire the identity is the authenticated dmsg PK, standalone it’s the TCP remote address for now. The framing codec (src/skydex/message) is a stdlib-only copy of skywire’s pkg/skychat/message so the wire format stays identical. 2952 Fix/UI test skydex design doc adds the SkyDEX design document and a skydex-ui test on the Linux CI job. This is the skycoin half of the migration; the companion skywire PR removes the engine from skywire and replaces it with thin appnet wrappers.