Back to list
Development Update — July 14
Today began with an audit of the transport bandwidth pipeline and found the rolled-up totals inflating throughput by roughly two — every network and per-visor aggregate had been reading a legacy combined field that summed both edges of a transport, each of which independently reports the full throughput. Fixing that read-side math corrected the dashboards immediately. A second transport-discovery bug explained why a freshly-booted visor’s routes 404’d for the first half-minute: the shared route-finder index was only refreshed on a 30-second ticker, so a new visor’s feed simply wasn’t subscribed yet — now it subscribes the moment the connection lands. Alongside the correctness work, transports gained a direction — every transport was originated by one side, and that in-versus-out distinction now shows in both the CLI and the hypervisor node list — the BTC-over-mesh gateway got its final blockers cleared and a health surface, and the wasm-visor’s auto-update became reliable enough to actually move connected tabs onto new builds. In the skycoin monorepo the same day cleared two of the daemon’s last TinyGo blockers — the real HTTPS API and the explorer — and landed the electrum and wallet-health source changes behind the gateway’s new connection surface.
Skywire: Transport-Discovery Correctness
3477 fix(tpd): stop double-counting network/visor bandwidth aggregates corrects a roughly 2× inflation in every rolled-up bandwidth total. Each edge of a transport reports the full transport throughput independently, so a per-transport redis hash keeps correct per-reporter fields but also a legacy combined bandwidth field that increments both reporters’ deltas — doubling any transport whose two edges both report. The per-transport metrics view was already correct because it reads the per-edge fields; the network dashboard total, the per-visor bandwidth sum and the single-transport daily total all read the doubled combined field. The fix routes all three through a new helper that takes a transport’s true daily throughput as the max across reporters of (sent+recv) — exact for a single-reporter transport, correct enough when both report — falling back to the combined field only for legacy rows. It also replaces a fabricated 50/50 sent/recv split (wrong for any asymmetric workload like a skysocks exit) with real stored sent and recv fields, and makes LogEntry.Reset() atomic. The read-side fixes correct existing redis data immediately. 3478 fix(tpd): subscribe to a visor feed on connect, not on the 30s poll fixes a related symptom: route find returning 404 “transport not found” for a just-booted visor even though its transport is registered, until it “warms up.” The route-finder shares the TPD’s redis, so this was never replication lag — the source visor’s edge-set was simply empty because the cxoaggregator’s reconcile loop, which subscribes to a connection’s feed and walks its published transport snapshot into redis, only ran on a 30-second ticker. Wiring the CXO node’s OnConnect callback to nudge an immediate reconcile means a freshly-connected visor’s feed is subscribed right away; the nudge coalesces bursts through a buffered channel and stays idempotent, with the periodic ticker kept as a safety net. 3476 fix(cli): route find over visor DmsgHTTP RPC, not CLI dmsg dial fixes the route find command itself, which built its own plain http.Client and died with “unsupported protocol scheme dmsg” because the route-finder is addressed by a dmsg:// URL. It now sends the /routes POST through the running visor’s existing DmsgHTTP RPC — the visor already holds a dmsg-capable client — and falls back to the old direct HTTP path only when no visor is reachable and the RF address is clearnet, while also guarding against an empty path set instead of blindly indexing [0].
Skywire: Incoming vs Outgoing Transports
3479 feat(cli): show incoming vs outgoing transports (tp -s / mode column) surfaces a distinction that was never recorded: a transport is bidirectional, but one side originated it — this visor either dialed out or accepted an inbound dial. ManagedTransport gains an isInitiator flag, set true where we dial and false where we accept, exposed through TransportSummary as a new initiator JSON field. In the CLI, tp -s now breaks each type into total, in and out with colored columns, and the existing mode column doubles as the direction indicator across all four table variants, so no new column and no format churn. Direction is correct by construction from the dial-versus-accept call sites, and against an old visor the absent field simply decodes as false without crashing. 3480 feat(hv-ui): show incoming vs outgoing transports in the node list carries the same field into the hypervisor UI’s Transports column, mapping initiator in both the node-list and single-node paths and rendering per-type counts with a green ↓ for incoming and a blue ↑ for outgoing; legacy placeholder-only nodes that predate transport summaries show just the total rather than a misleading 0/0 split. 3491 fix(wasm-visor): populate transport Initiator so HV-UI in/out direction is correct fixes a wasm-side gap where every browser-visor transport showed as incoming — backwards, since a browser visor can only dial out, the sole exception being an accepted WebRTC. The wasm visor builds its own mirror TransportSummary struct, which had never carried the initiator field; adding it and setting it from IsInitiator() in both the self-enumeration and the add-transport controller makes the node list render, for example, SWTR 0↓ 2↑ and WEBRTC 1↓ 0↑. 3490 chore(wasm): re-embed blob so the wasm visor reports transport direction rebuilt the committed blob for the same reason — it had drifted behind develop and predated the direction work — though the deeper fix was the mirror-struct field in #3491.
Skywire: Finishing Bitcoin Over the Mesh
3474 chore(btc): vendor electrum self-signed-cert fix + rebuild wasm cleared the last certificate blocker: the gateway failed every self-signed ssl:// electrum server with x509: certificate is not valid for any names, so vendoring the skycoin fix that skips CA verification — electrum servers routinely use self-signed certs — let the TLS handshake complete once the skysocks route and TCP connect already worked. 3475 chore(btc): vendor 90s electrum mesh timeout + rebuild wasm cleared the piece after that: with the cert fix in place the TLS handshake succeeded, but the electrum protocol handshake over a multihop route plus skysocks plus in-tab TLS blew the 30-second deadline, so a 90-second client timeout for mesh-tunnel dialers was vendored, completing the traced route → TCP → TLS → electrum-handshake chain. 3473 fix(wasm): fail fast (18s) on skysocks route setup instead of 45s caps a skysocks-lite route setup to a dead exit at 18 seconds instead of 45 — a reachable exit establishes in a few seconds, and since most random SD exits aren’t routable from a browser visor, failing fast lets the wallet’s BTC egress or the iframe browser move on to another. 3492 fix(wallet): route skycoin-web’s /api/v1/btc/* to the BTC gateway, not the node fixes BTC balance, history and send being broken in the browser wallet while only the health strip worked: skycoin-web’s ApiService prefixes /api/v1/, so it fetches btc/balance as /api/v1/btc/balance, but both shims classified BTC with an anchored regex that only matched /v1/btc/, sending those requests to the skycoin node — which has no such endpoint. Reclassifying BTC as “path contains /v1/btc/”, checked before the node branch, covers both forms; the genesis address’s 57.225 BTC now returns end-to-end.
Skywire: Wallet Health and Node Convergence
3481 feat(wallet): /v1/btc/health + connection-log visibility; vendor skycoin health/UI is the skywire half of a coordinated connection-health effort. It adds a GET /v1/btc/health endpoint returning the electrum tip height (502 when the server is unreachable) for both native and wasm, makes both wallet shims log every node and BTC request and its outcome — status and timing — to the shared log with a [wallet] prefix so the config page’s live log pane shows what is crossing the mesh even at the seed-entry screen, and re-embeds a skycoin-web build carrying an always-visible node/electrum status bar and create-wallet coin-availability gating. 3483 feat(wallet): shim honors skycoin-web’s Nodes-GUI node selection converges node selection onto skycoin-web’s own Settings → Nodes page as the authoritative source, instead of the shim overriding every /api call with a parallel skywire key that silently made the Nodes page a no-op. Both shims now take the coin node from the URL skycoin-web addressed the request to — its Nodes page makes the fetch URL absolute — routing dmsg for a .dmsg host and skysocks for clearnet, and falling back to the legacy config key only for a relative same-origin path so nothing breaks. 3484 chore(wallet): vendor skycoin@16104d93 + re-embed (node-config convergence) then re-embedded the wallet so the status bar follows that effective node, completing the convergence where Settings → Nodes is authoritative and the skywire config panel is a fallback.
Skywire: Reliable Wasm Auto-Update
3482 fix(wasm-hv): reliable auto-update (background + SharedWorker) + align transport counts fixes two reasons a served wasm-visor could stay on an old build. The updater polled /wasm-version with a setInterval that browsers throttle in background tabs and freeze on discard, so an unfocused tab could miss a new build for a long time — it now also re-checks on visibilitychange and pageshow and once shortly after boot. More subtly, the runtime lives in a SharedWorker that survives location.reload(), so a reloaded page reconnected to the stale worker; adding a shutdown path that the updater posts before reloading makes the post-reload page boot a fresh worker that fetches the new wasm. It also lays the node-list per-type in/out counts out as a fixed grid so the ↓/↑ columns line up instead of shifting with each type name’s width. 3485 fix(hv-serve): /wasm-version fingerprints the whole build, not just the wasm blob fixes the complementary detection gap: /wasm-version hashed only the wasm blob, so a UI-only, serve-only or plain version-bump deploy — where the blob is byte-identical — never moved the fingerprint, and connected tabs stayed on the old build even though the server was already serving the new one. The fingerprint is now the hash of the wasm blob plus the Angular index plus the build version, so any deploy moves it.
Skywire: Documentation
3487 docs(forwarding): run any app over skynet/dmsg — with/without Caddy + browser access expands the forwarding doc into the generic “run any app over skynet/dmsg” recipe — the far-end forward and near-end resolving proxy, hosting HTTP apps with the built-in port-80 proxy versus Caddy or nginx with --preserve-host for many vhosted sites (node.skycoin.com as the worked example), and a new section on reaching a served app via both cli got and the browser’s resolving SOCKS5 proxy. 3488 docs(forwarding): point to the existing websites guides instead of duplicating them then trimmed the overlap, since the Caddy, vhost and base32 material already lives in the website-auth and skynet-tls guides, keeping a clean split: port forwarding here, websites over skywire in those two.
Skycoin: A Real HTTPS API and Explorer Under TinyGo
Two of the daemon’s last TinyGo blockers fell today, both about reflection the fork now supports or that a build tag can route around. The API’s HTTPS interface goes universal: the 0magnet/tinygo fork’s develop branch now uses Go’s software crypto/tls on the native target, so tls.Listen / tls.LoadX509KeyPair work — the https_tinygo.go stub returning ErrHTTPSUnsupported is dropped, CreateHTTPS builds everywhere, and a TinyGo-built daemon was verified serving the API over TLS 1.3. The explorer’s only remaining blocker was rendering its API-docs page with html/template in init(), which needs reflect.Type.NumOut func-signature introspection TinyGo doesn’t implement; moving just that into a build-tagged renderDocs (html/template on !tinygo, a static notice under tinygo) lets the whole command build, and root.go / pprof.go become universal now that net/http/pprof works under TinyGo — the explorer’s block/tx views, API proxy, static frontend and pprof all run normally, and the whole-command root_tinygo.go stub is gone.
Skycoin: Electrum Over the Mesh, and Health at the Seed Screen
Two vendored electrum fixes cleared the last certificate and timeout blockers for Skywire’s BTC-over-mesh gateway (its #3474 / #3475). 2936 electrum: skip CA verification (self-signed certs are the norm) sets InsecureSkipVerify (SNI still sent) because public electrum servers overwhelmingly present self-signed certs — the protocol uses TLS for transport encryption, not CA authentication, and the reference client pins them out of band — so the near-universal x509: certificate is not valid for any names handshake failure goes away. 2937 btc: 90s electrum timeout for mesh-tunnel dialers (was 30s) bumps the handshake deadline: carried over a multihop Skywire route plus skysocks plus in-tab TLS, server.version’s several high-latency round-trips blew the 30s limit, while clearnet still completes in well under a second.
Alongside them, a coordinated connection-health effort landed the skycoin half of what Skywire’s #3481 wires up. 2938 feat(wallet): node/electrum connection health at seed-entry + coin-availability gating surfaces backend reachability before a wallet exists — the seed-entry / create screen covers everything, so there’s nothing to query, but a node’s health (chain head) tells you plenty. It adds btc.Backend.Health() (tipHeight, error) (plus electrum.Client.HeadersSubscribe() via blockchain.headers.subscribe; Core via getblockchaininfo), the BTC parallel to the skycoin node’s /api/v1/health; a NodeHealthService that probes a coin’s backend over the same request paths the wallet already uses, so a visor’s fetch shim routes them over the mesh transparently and it never throws; an always-visible NodeStatusBarComponent strip above the router outlet showing the current coin’s connection and chain tip on every screen, polling every 20s; and a soft coin-availability gate on the create form that warns rather than blocks, since wallet creation is client-side. 2939 feat(wallet): node health follows the effective (custom) node + Nodes-page help then converges node config onto skycoin-web’s own Settings → Nodes GUI (customNodeUrls) as the single source of truth: NodeHealthService now probes the effective node — a per-coin custom URL overrides the default exactly as ApiService resolves it for the wallet’s own calls — so the status bar reflects the node the wallet is actually talking to, and the Nodes page gains help text explaining that a Skywire mesh node is set with an http://<name>.<base32-pk>.dmsg URL. Both rebuild src/gui/dist; Skywire’s #3483 is the matching shim change that honors this node instead of overriding it with a parallel key.