fix: initialize the servers before publishing their addresses (7.0.1:1) - #25
Merged
Conversation
MattDHill
force-pushed
the
fix/relay-address-before-init
branch
from
August 28, 2026 20:09
cc37436 to
6e7dd80
Compare
`setInterfaces` ran third in the init chain and `initServers` fifth, so on install the interfaces pass read the CA fingerprint and the auth password before `smp-server init` had written either. Both are interpolated into `username`, so the pass published `smp://undefined:null@host:5223` — a well-formed address no client can authenticate against — until the `.const()` watches re-ran it. The window is two subcontainer spawns doing keypair generation wide, and it recurs on every reinstall. `initServers` is a seed step: it reads no host or interface state, only volumes and file models, while `setInterfaces` consumes what it writes. Hoisting it above `setInterfaces` closes the window, and matches how lnd and cln order their own seed steps. Nothing guards the reads, because after the reorder nothing can reach them empty: `execFail` throws if `smp-server init` fails, the non-install path already throws when the ini has no `create_password`, and `setupInit` propagates either — so a failure aborts init rather than reaching `setInterfaces`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MattDHill
force-pushed
the
fix/relay-address-before-init
branch
from
August 28, 2026 20:12
6e7dd80 to
f249192
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On install, the SMP and XFTP addresses were published as:
Well-formed enough for a client to accept and store, and impossible to authenticate against.
Cause: init order, not a race
setupInitruns handlers sequentially, so on a fresh installsetInterfacesexecuted beforesmp-server inithad ever run.smp-configsis empty at that point — nofingerprintfile, nosmp-server.inito readAUTH.create_passwordfrom — and both empty reads were interpolated straight intousername.The pass does re-run on its own, since both reads are
.const()andsetupInitgives each handler aconstRetry. But the window it corrects is two subcontainer spawns doing keypair generation wide, and it recurs on every reinstall — with a fresh CA on the other side.Fix
initServersmoves abovesetInterfaces. It's a seed step: it reads no host or interface state, only volumes and file models (smpMounts/xftpMountsare plain volume mounts), whilesetInterfacesis the thing that consumes what it writes. The dependency only ever ran one way. This matches howlndandcln— the other two packages whosesetInterfacesreads generated files — order their own seed steps ahead of it.That's the whole change. The reads are left unguarded, because after the reorder nothing can reach them empty:
execFailthrows ifsmp-server initfails, the non-install path already throws when the ini carries nocreate_password, andsetupInitawaits each handler without catching — so either failure aborts init rather than arriving atsetInterfaceswith nothing to read.(
lndandclndo guard their equivalent reads, but for a condition this package doesn't have: their credentials are deleted and re-minted at runtime by rune revocation and macaroon rotation, so both pass a customeqto ignore the gap. Nothing here ever removes the fingerprint.)Bumped to
7.0.1:1; wrapper-only, no migration.How it surfaced
simplex-websocket-bridge-startosresolves this interface as its Local relay and picked up theundefined:nullform while following a reinstalled server to its new address. It landed a fingerprint-shape guard on its side (Start9-Community/simplex-websocket-bridge-startos#14) — worth keeping regardless, since a consumer shouldn't trust a relay URI's shape — but the malformed value originated here.Related: Start9Labs/start-technologies#3861 fixes the SDK-side reason the bridge stopped noticing address changes at all.