Skip to content

Start9 (StartOS) package + StartOS-driven binary fixes (v0.3.15)#4

Merged
criptoworld8484 merged 20 commits into
masterfrom
start9-adaptation
Jun 27, 2026
Merged

Start9 (StartOS) package + StartOS-driven binary fixes (v0.3.15)#4
criptoworld8484 merged 20 commits into
masterfrom
start9-adaptation

Conversation

@criptoworld8484

Copy link
Copy Markdown
Owner

Summary

Adds a StartOS (.s9pk) package for Broadcast Pool under start9/, plus the binary fixes that testing on a live Start9 node surfaced. Verified end-to-end on a Start9 testnet4 node (Bitcoin Core + Fulcrum).

StartOS package (start9/)

  • TS SDK package mirroring sparrow-frigate-startos: depends on bitcoind + fulcrum; exposes an Electrum (TCP) interface on 50050 (shared by Sparrow and Liana) and a web dashboard; entrypoint maps the StartOS env (bitcoind cookie, fulcrum.startos) to the binary's generic BROADCAST_POOL_* contract. Network auto-detected from Bitcoin Core (mainnet/testnet4/signet). x86_64 (base image is amd64; aarch64 is a follow-up).

Binary fixes (general, not Start9-specific)

Test plan

  • cargo test --bin broadcast-pool — 32 pass
  • Live on Start9 testnet4: install, network auto-detected, genesis matches, Sparrow (3 modes) and Liana (manual/pending, schedulable) verified on the single port 50050; dashboard guidance correct.

Supersedes #2 and #3 (their changes are included here).

🤖 Generated with Claude Code

criptoworld and others added 20 commits June 25, 2026 21:49
Mirror the sparrow-frigate-startos TS SDK pattern under start9/, wrapping the
same Rust binary. Maps StartOS config (bitcoind cookie, electrs.startos host,
mainnet) to the binary's generic BROADCAST_POOL_* env vars. Isolated on the
start9-adaptation branch; does not touch Umbrel packaging.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Wraps the same Rust binary in a StartOS package under start9/, mirroring the
proven sparrow-frigate-startos TS SDK structure. Depends on bitcoind + electrs;
exposes an Electrum (TCP) interface on 50050 for Sparrow/Liana and a web UI on
8080. entrypoint.sh maps the StartOS env (bitcoind cookie, electrs.startos host)
to the binary's generic BROADCAST_POOL_* contract.

Network (mainnet/testnet4/signet) is auto-detected from Bitcoin Core. To make
pure auto-detection correct, src/main.rs now runs RPC creation + network
detection BEFORE deriving the network-specific data dir and opening the DB
(previously the DB could open on the wrong network when BROADCAST_POOL_NETWORK
was unset). No-op for Umbrel, where the network is provided.

Verified locally: cargo tests (27) pass; the StartOS TypeScript type-checks
against @start9labs/start-sdk 1.5.3 and bundles via ncc; entrypoint.sh passes
sh -n. Full .s9pk build + live mainnet smoke test run via CI + the Start9 node.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Resolves the s9pk ingredient path mismatch: the docker build context must be the
package dir (start9/), which lacks the Rust source. Idiomatic StartOS packaging
builds from a prebuilt artifact, so base the image off the already-published
broadcast-pool-umbrel image and overlay the StartOS entrypoint/env. That image is
linux/amd64 only, so v1 ships x86_64; aarch64 is a follow-up.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Validated on the live Start9 node (StartOS 0.4.0-beta.9, testnet4): the installed
indexer is Fulcrum (Electrum TCP on fulcrum.startos:50001), not electrs, and
Bitcoin Core RPC is normalized to bitcoind.startos:8332 on every network (so the
testnet4 default-port concern is moot). Cookie is __cookie__:... at testnet4/.cookie
under the bitcoind mount (handled by the entrypoint's recursive find).

- manifest/dependencies: electrs -> fulcrum (health checks primary, sync-progress).
- entrypoint: indexer default -> tcp://fulcrum.startos:50001.
- drop the bitcoind autoconfig task (Fulcrum already requires an archival node).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
The live node showed 'cannot create /data/startos-boot.log: Permission denied':
StartOS 0.4 runs service subcontainers as root with a root-owned data volume, but
the base image trailing USER app (uid 1000) couldn't write /data. Run as root.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
connect_stream/fetch_prev_tx/forward_to_indexer_sync used str::parse::<SocketAddr>,
which only accepts literal IPs. Umbrel passes an IP (10.21.21.10) so it worked, but
StartOS passes a hostname (fulcrum.startos:50001) and parse() failed with 'Invalid
indexer address' -> the binary reported 'tried TCP and SSL' and never connected to
the indexer, even though it was reachable. Add resolve_socket_addr() using
to_socket_addrs() (handles hostnames AND IPs) and use it in all three connect sites.

Found on the live Start9 node (testnet4, Fulcrum at fulcrum.startos:50001).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
The dashboard showed the StartOS overlay IP (10.0.3.x) as the wallet URL — useless
for Sparrow/Liana — and the warning text was hardcoded to 'Umbrel'.

- discovery: exclude the StartOS overlay (10.0.3.x) from detect_lan_ip (it already
  excluded Umbrel/docker ranges) so a bogus container IP is never shown; also apply
  the exclusion to the 'ip route get' path. Add is_startos_mode() (reads
  BROADCAST_POOL_PLATFORM=startos, set by the StartOS entrypoint).
- api: expose startos_mode in the config response.
- dashboard: generic wallet warning (node LAN IP, electrs/Fulcrum) instead of Umbrel;
  on StartOS show guidance to use the Electrum (TCP) address from the service's
  Interfaces page rather than a (non-routable) container IP.
- start9 entrypoint: export BROADCAST_POOL_PLATFORM=startos.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
… (v0.3.14)

An earlier version persisted the StartOS overlay IP (10.0.3.x) into config.toml's
lan_connect_host, so resolve_lan_host kept returning it even after detect_lan_ip was
fixed. Reject overlay/bridge IPs when reading the persisted host too.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Liana always sets a block-height nLockTime (anti-fee-sniping; not disableable like
Sparrow's MTP), so a tx sent to the shared Sparrow port (50050) was categorized
'by_block'. The binary already has a dedicated 'liana' listener (source=liana ->
manual/pending); expose it as a separate StartOS Electrum interface on 50051 and set
BROADCAST_POOL_LIANA_ELECTRUM_PORT in the entrypoint. Liana points at this port so its
txs arrive pending and can be scheduled by date/time from the dashboard.

Package-only change (binary unchanged, still :0.3.14); s9pk revision 0.3.14:2.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Premise: Sparrow and Liana use the SAME Electrum port (50050). Liana always sets a
block-height nLockTime (anti-fee-sniping, not disableable like Sparrow's MTP), so its
tx was categorized 'by_block' instead of manual/pending — the user couldn't schedule
a date/time for it.

Distinguish the wallets on the shared port: Sparrow always sends server.version during
its handshake; Liana (electrum-client/Rust) skips it. Track saw_server_version + the
client name per session; at broadcast time, a Sparrow-port session that never sent
server.version (or whose client name is Liana) is attributed to 'liana' → ingested as
manual/pending (date/time scheduling; price scheduling already excluded for non-zero
nLockTime). Sparrow's own by_block mode is unaffected (it always sends server.version).

Reverts the separate-port StartOS interface (50051) — same port for both, per the premise.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
# Conflicts:
#	Cargo.lock
#	Cargo.toml
@criptoworld8484 criptoworld8484 merged commit 51bcba9 into master Jun 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant