<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinos-server.git/lib/ln.ts, branch master</title>
<subtitle>coinos server — legacy coinos.io backend (Lightning, on-chain, Liquid)</subtitle>
<id>https://git.coinos.io/coinos-server.git/atom?h=master</id>
<link rel='self' href='https://git.coinos.io/coinos-server.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/'/>
<updated>2026-08-16T06:16:28Z</updated>
<entry>
<title>ln: tear down dead cl clients fully + recover invoice listener on socket death</title>
<updated>2026-08-16T06:16:28Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-16T06:16:28Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=7c6805decc508b009673e1a5651b2a86ebdef717'/>
<id>urn:sha1:7c6805decc508b009673e1a5651b2a86ebdef717</id>
<content type='text'>
Replace bare `client = null` with dropClient(): stop the clightning-client
library's internal reconnect loop (clear reconnectTimeout, neuter reconnect,
destroy the socket, drop listeners). A dead client was otherwise orphaned and
spun forever retrying `connect ENOENT`, spamming logs and leaking a socket+timer
on every cl restart. Guard the error handler on `c === client` so a stale
client's late error can't drop a newer, healthy one.

Add lnListen.onDrop so the invoice listener recycles immediately when its
long-poll socket dies (bump epoch, re-arm) instead of waiting up to 5 minutes for
the stall watchdog. Stop counting LightningUnavailableError toward the listener's
process.exit escalation, so a cl restart no longer makes the app self-exit — it
retries until cl returns.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>ln/lightning: watchdog recycles zombie receive-listener socket</title>
<updated>2026-06-05T01:17:47Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-06-05T01:17:47Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=bd1ece38e42751575ac2e03a5c795b5b109653ac'/>
<id>urn:sha1:bd1ece38e42751575ac2e03a5c795b5b109653ac</id>
<content type='text'>
On 2026-06-04 cl restarted (autoheal, after its 15s healthcheck timed out),
and the app's waitanyinvoice long-poll hung on the now-dead listen socket.
listenerActive stayed true forever, so ensureListenerAlive never restarted
it, and incoming lightning payments stopped crediting for ~2h until a manual
app restart. The per-call RPC timeout in ln.ts can't catch this: waitanyinvoice
is intentionally in NO_TIMEOUT (it's meant to block).

Fix: ensureListenerAlive (runs every 120s) now also detects a stalled listener
— active but blocked in waitanyinvoice for &gt;5min. It probes cl via the main
ln socket (getinfo); only if cl is actually alive does it treat the listen
socket as a zombie, call lnListen.reset() (new: drops the proxy's socket so the
next call reconnects), and re-arm. A listenerEpoch guard makes the wedged
invocation bow out when its waitanyinvoice finally rejects, so we never run two
listeners concurrently and never double-credit. Verified with a state-machine
test covering normal receive, quiet-but-healthy (left alone), stall+cl-alive
(recycled), stall+cl-down (left alone), and the no-double-listener race.

Co-Authored-By: Claude Opus 4.8 (1M context) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>ln: time out short-lived RPCs so a hung cl reconnects without restart</title>
<updated>2026-06-01T06:28:12Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-06-01T06:28:12Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=a664af99dfee8267a960fd22cbab852681198de2'/>
<id>urn:sha1:a664af99dfee8267a960fd22cbab852681198de2</id>
<content type='text'>
A unix-domain RPC socket has no TCP keepalive, so if cl goes
unresponsive while the socket stays open (zombie/half-open), an awaited
call hangs forever — the "stuck spinner past /pay/bob, no error"
symptom. Nothing threw, so the existing reconnect-on-error path never
fired and only an app restart recovered it.

Wrap short-lived calls in a 30s Promise.race timeout (matching
health.ts). A timeout rejects with ETIMEDOUT, now part of isSocketDied,
so the client is dropped and the next call reconnects — no process
restart. Long-polls (waitanyinvoice et al), in-flight payments
(pay/xpay/sendpay/keysend), and bolt12 round-trips (fetchinvoice/
sendinvoice/offer) are exempt: timing those out client-side would risk
leaked debits or break intentional blocking.

Co-Authored-By: Claude Opus 4.8 (1M context) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>adjust ln minfee</title>
<updated>2026-03-15T22:49:17Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2026-03-15T22:49:17Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=74af7b1d0922e740c0358dfd131776fd7c877767'/>
<id>urn:sha1:74af7b1d0922e740c0358dfd131776fd7c877767</id>
<content type='text'>
</content>
</entry>
<entry>
<title>handle socket errors</title>
<updated>2026-02-25T20:06:04Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2026-02-10T19:31:36Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=0d76a676e8dba58b42f52d6b8b990bf9954db784'/>
<id>urn:sha1:0d76a676e8dba58b42f52d6b8b990bf9954db784</id>
<content type='text'>
</content>
</entry>
<entry>
<title>health check</title>
<updated>2026-02-06T16:55:45Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2026-02-06T16:55:45Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=9089698e8df9d0c09c165c45eb6b05335a818699'/>
<id>urn:sha1:9089698e8df9d0c09c165c45eb6b05335a818699</id>
<content type='text'>
</content>
</entry>
<entry>
<title>more robust lightning client</title>
<updated>2025-12-16T21:42:42Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2025-12-16T21:42:42Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=52fb26dbaf6a169cc63c50d480d3e7a9a999854c'/>
<id>urn:sha1:52fb26dbaf6a169cc63c50d480d3e7a9a999854c</id>
<content type='text'>
</content>
</entry>
<entry>
<title>xpay</title>
<updated>2024-11-27T08:16:18Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2024-11-27T08:16:18Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=430b17d26fa3fe2ef31c6fb0850882a9fd4c830c'/>
<id>urn:sha1:430b17d26fa3fe2ef31c6fb0850882a9fd4c830c</id>
<content type='text'>
</content>
</entry>
<entry>
<title>save ecash id</title>
<updated>2024-10-24T20:59:34Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2024-10-24T20:59:34Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=d09712ef8f8ea8218ce229b233fc0013e6c06f7a'/>
<id>urn:sha1:d09712ef8f8ea8218ce229b233fc0013e6c06f7a</id>
<content type='text'>
</content>
</entry>
<entry>
<title>typescript</title>
<updated>2024-08-27T04:17:43Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2024-08-27T04:17:43Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinos-server.git/commit/?id=fe62cadd6fb4a7e49f7d59401fc74ae0411e32a7'/>
<id>urn:sha1:fe62cadd6fb4a7e49f7d59401fc74ae0411e32a7</id>
<content type='text'>
</content>
</entry>
</feed>
