Commit graph

922 commits

Author SHA1 Message Date
Ken Sedgwick
0c35900ad9
Merge pull request #331 from ksedgwic/restore-jit-inflight-guard
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
JitRebalancer: restore the in-flight guard lost in the #328 squash
2026-08-14 13:21:07 -07:00
Ken Sedgwick
6fe275ad70
JitRebalancer: restore the in-flight guard lost in the #328 squash
The #328 squash commit (986f30d) was created by soft-resetting the
autoclose branch onto origin/master, but the branch's index still held
a tree from before the #327 merge, so the commit silently reverted
Boss/Mod/JitRebalancer.cpp and tests/boss/test_jitrebalancer.cpp to
their pre-guard state.  master and the v0.16.3-rc1 tag therefore lack
the fix for #323 that the CHANGELOG describes.  GitHub's up-to-date
check passed because it checks ancestry, not tree content, and CI
passed because the guard's tests were reverted along with the guard.

Restore both files from the post-#327 master tip (5839241); nothing
else has touched them since, and git diff 5839241 986f30d confirms
the reversion was limited to these two files.

Restores the fix for #323.
2026-08-14 12:33:57 -07:00
Ken Sedgwick
4fa29b0e21
update version and CHANGELOG for v0.16.3
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
AC_INIT 0.16.2 -> 0.16.3; CHANGELOG gains the 0.16.3 Security
section covering the reverse-swap claim UPDATE scoping (#325), the
JitRebalancer per-destination in-flight guard (#323), and the
auto-close offline-peer patience rework (#324).  Release date and
codename land in the follow-up commit at final release time.
2026-08-13 15:16:07 -07:00
Ken Sedgwick
d2692890dd
Merge pull request #328 from ksedgwic/autoclose-defer-offline
PeerComplaintsDesk: defer auto-close while the peer is offline
2026-08-13 13:48:06 -07:00
Ken Sedgwick
986f30d1b4
PeerComplaintsDesk: defer auto-close while the peer is offline
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
close was issued with unilateraltimeout=180 on a fixed timer,
without regard to the peer's connection state, while one complaint
source (ComplainerByLowConnectRate) selects peers specifically for
a low connect rate.  Closing while the peer is offline escalates
to a unilateral force-close after 3 minutes, against exactly the
peers least likely to negotiate a mutual close in time.

Check the peer's channels for a live connection (listpeerchannels
peer_connected) before issuing close, and defer while the peer is
offline.  Poll close candidates every 10 minutes rather than once
per solicitation cycle, so a flaky peer's brief online windows are
actually caught.  If the peer stays offline for close_patience
(3 days), close anyway and let the short unilateral timeout
escalate; the first-deferred time is persisted in a new
PeerComplaintsDesk_closepending table so restarts do not reset
the patience window.  The fees_low gate applies only to that
unilateral path: a mutual close even at high feerates is cheaper
than a unilateral at low feerates, so connected peers are closed
immediately regardless of feerate.

Add tests/boss/test_peercomplaintsdesk_main.cpp covering the close
paths: a connected peer closes immediately; an offline peer defers
and the deferral survives a restart; within patience it holds;
expired patience holds at high fees and closes at low fees;
dropping below the complaint threshold sweeps the deferral;
channel destruction clears it; disabled auto-close closes nothing.
The test drives the module over the bus with a mock CLN on a
socketpair.

Reported by an external security researcher via private disclosure.

Fixes #324
2026-08-13 13:18:04 -07:00
Ken Sedgwick
583924184c
Merge pull request #327 from ksedgwic/jit-inflight-guard
JitRebalancer: skip rebalance if one is already in flight for the destination
2026-08-13 12:24:45 -07:00
Ken Sedgwick
16ac283abb
JitRebalancer: skip rebalance if one is already in flight for the destination
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
The fee budget check reads out_expenditures, which is only
persisted once a rebalance completes (up to 120 s per run).  Each
incoming HTLC spawned an independent rebalance run with no guard,
so concurrent HTLCs to the same underfunded channel each passed
the check against the same stale value, multiplying the intended
25%-of-earnings aggregate cap by the number of concurrent triggers.

Skip HTLC-triggered rebalances for a node that already has one in
flight, mirroring the working guard in EarningsRebalancer.  Skipped
HTLCs are released immediately and proceed without JIT rebalancing;
a retry after the in-flight run completes sees both the refilled
channel and the updated budget.

Update the parallel-calls unit test to the new semantics: exactly
one of three concurrent calls is let in, only it requests a
rebalance, and the guard clears once the run completes.

Reported by an external security researcher via private disclosure.

Fixes #323
2026-08-13 12:05:06 -07:00
Ken Sedgwick
52c179d43d
Merge pull request #326 from ksedgwic/reverse-swap-problem
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
Boltz/Detail/ClaimTxHandler.cpp: Scope claim db update to the claimed swap.
2026-08-12 15:13:54 -07:00
Ken Sedgwick
99c0592612
tests/boltz/test_claimtxhandler_scoped_update.cpp: Also cover the apiAccess predicate.
Both inserted rows used the same apiAccess, so the test would not
catch a claim UPDATE scoped by swapId alone.  Add a third row
sharing swapA's swapId under a different apiAccess; the
single-stamped-row count assertion now fails if either predicate
is dropped.  Verified: a swapId-only variant fails the count
assertion.

Prompted by review on #326.
2026-08-12 14:55:09 -07:00
Ken Sedgwick
9075ee32fc
Boltz/Detail/ClaimTxHandler.cpp: Scope claim db update to the claimed swap.
After broadcasting a reverse-swap claim transaction, the handler
recorded the claim with an UPDATE that had no WHERE clause, marking
every row in BoltzServiceFactory_rsub lockedUp=1.  Any other in-flight
swap then took the "Already broadcasted claim tx." early exit and
never broadcast its own claim; its off-chain payment stayed unsettled
until the timeout/refund path unwound it.

Add the same apiAccess + swapId predicates used by the neighboring
SELECTs and DELETE, and a regression test that seeds two swaps,
claims one, and asserts the sibling row is untouched.  The test
fails before this change and passes after.

Reported by Vincenzo Palazzo (Bitcoin Security Council / Sentinel).

Fixes #325.
2026-08-12 13:25:31 -07:00
Ken Sedgwick
6dab027986
Update CHANGELOG release date for v0.16.2
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
2026-08-11 16:48:26 -07:00
Ken Sedgwick
9fb9115dd0
update version and CHANGELOG for v0.16.2
Bump AC_INIT to 0.16.2 and add the CHANGELOG entry for the FundsMover
self-payment amount-verification fix. (#322)
2026-08-11 15:22:48 -07:00
Ken Sedgwick
3c8dc3c16d
FundsMover: verify incoming amount before resolving self-payment HTLCs
The claim of a returning self-payment matched payment_hash and
payment_secret but not the HTLC amount.  Answering the hook with
resolve settles the HTLC at once, so lightningd's own
final_incorrect_htlc_amount check is skipped.  The last-hop peer
relays our onion (and thus the secret) intact but chooses the offered
amount, so it could settle a reduced HTLC, learn the preimage, and
claim the full amount upstream.

Record the intended amount at Claimer::generate() time and resolve
only an exact match; a mismatch is left to normal handling, which
fails the HTLC for lack of an invoice.

The same issue was recently fixed in sling (daywalker90/sling@835f36e8).

Fixes #322.
2026-08-11 14:56:24 -07:00
Ken Sedgwick
2fb5c8b0b0
Update CHANGELOG release date for v0.16.1
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
2026-08-06 18:04:56 -07:00
Ken Sedgwick
04fc498b67
update version and CHANGELOG for v0.16.1
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
Bump AC_INIT to 0.16.1 and add the CHANGELOG entry for the two
point-release fixes from issue #321: tolerate the missing old_state
field in channel_state_changed notifications, and request p2tr
addresses from newaddr.
2026-08-06 16:44:58 -07:00
Ken Sedgwick
1c3ac637ec
Boss/Mod/NewaddrHandler.cpp: Request p2tr addresses (CLN bech32 default removed).
CLN deprecated and then removed the implicit-bech32 default for the
newaddr command. Modern CLN (tested on v26.04.1) responds to
newaddr with only {"p2tr": "..."} and prints the warning

  jsonrpc: Note: disallowing deprecated newaddr.addresstype.defaultbech32

This hit our existing code at line 38, which extracted res["bech32"]
unconditionally. Jsmn::Object::operator[] returns an Object with
null pimpl when the key is missing, and the std::string conversion
operator then throws TypeError. The exception propagates up the
Ev::Io chain and is swallowed silently, so Msg::ResponseNewaddr is
never raised.

Downstream symptom: SwapManager hangs forever in state 0
(NeedsOnchainAddress) after restart. Its getting_address flag was
set true when it raised the request, and only clears when the
queue empties via the response chain that never completes. Every
subsequent Timer10Minutes tick short-circuits on the still-true
flag and does nothing.

Fix matches the draft on origin/boltzapi-v2-taproot-reverse-swaps
commit c3dd1de: explicitly request newaddr p2tr and read res["p2tr"].
This is a breaking change for CLN v23.05 and older, but those are
two-plus years out of support already.
2026-08-06 16:42:23 -07:00
Ken Sedgwick
157ec0e935
ChannelCreateDestroyMonitor: tolerate missing old_state (CLN v26.06)
CLN's channel_state_changed notification used to emit the sentinel
value "unknown" for old_state when there was no previous state.
That value was deprecated in v25.05 and is last-supported in v26.04;
as of v26.06 the old_state field is simply omitted instead (see
doc/developers-guide/deprecated-features.md, entry
"channel_state_changed.old_state.unknown").

The notification handler unconditionally extracted old_state, which
throws Jsmn::TypeError when the field is absent.  The throw was
caught by the surrounding handler, logged as Error
("Unexpected channel_state_changed payload: ..."), and then the
handler returned without taking action.  Functional behavior was
unchanged compared to the legacy "unknown" path (both result in
no destruction event), but the new release variant produced noisy
Error log lines for every state-changed notification on nodes
running v26.06+.

Add an explicit has() check and leave old_state as the default
empty string when absent.  The empty string will not match either
"CHANNELD_NORMAL" or "CHANNELD_AWAITING_LOCKIN", so the handler
falls through to the no-op return -- the same outcome the legacy
catch-and-log path produced, but silently.

This is the third and final commit of the v26.06 compatibility
PR (preceded by the Dowser and Matchmaker/ActiveProber commits).
2026-08-06 16:41:57 -07:00
Ken Sedgwick
a759a54ac7
Add SECURITY.md
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
Establish a private channel for vulnerability reports: email to
ken@bonsai.com encrypted to the listed GPG key.  The policy states a
72-hour acknowledgment window, asks for coordinated disclosure, and
lists the contact key with import instructions.
2026-08-04 10:34:36 -07:00
Ken Sedgwick
f9a91fec7e
Merge pull request #308 from ksedgwic/2026-03-use-avg-for-fwdstats
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
contrib: Improve the clboss-forwarding-stats Utility
2026-06-23 10:29:40 -07:00
Ken Sedgwick
1a6d0f1974
contrib/clboss-forwarding-stats: validate --days and --db CLI inputs
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
- --days must be a strictly positive integer. Reject 0 and negative
    values which would push window_start_ts into the future or get
    silently treated as unset.

  - --db, when provided, must reference an existing file. Raise a
    clear argparse error at startup instead of bubbling up as a
    sqlite OperationalError later from inside the feemon loader.
2026-06-22 16:42:50 -07:00
Ken Sedgwick
18273b933c
contrib/clboss-forwarding-stats: rework FRAL/TRAL on avg liquidity
Rename the per-peer forwarding metric from FPBPD to FRAL (Forwarding
Rate on Average Liquidity), and TRCL to TRAL (Trailing Return on
Average Liquidity). Both are now computed against avg_to_us_msat and
OpDays rather than the previous current-balance and clamped peer-age
divisors, which gives a more honest per-active-day rate for channels
that were closed and reopened.

Adds a --sort {fral,tral} option (default fral) so the user can pick
the ranking metric, a 1-OpDay floor in both calculations to suppress
nonsense ratios from brand-new channels, and a footnote legend at the
bottom of the table describing what each metric means.
2026-06-22 16:42:49 -07:00
Ken Sedgwick
fdc5523266
contrib/clboss-forwarding-stats: feemon DB integration and avg liquidity
Add an optional --db argument pointing at the feemon sqlite DB. When
present, fetch feemon records for each peer over the chosen window (one
extra day earlier than window_start_ts, so a boundary balance record
exists for the window start) and compute two new per-peer quantities:

  - avg_to_us_msat: time-weighted average of our-side balance over
    the window, used as the liquidity divisor for forwarding metrics
    instead of the instantaneous current balance.

  - OpDays: operational days estimated from the feemon record count
    (~1/hour, so count / 24), used to prorate per-peer rates when a
    channel has only been open for part of the window.

Both are surfaced as new columns in the output table.
2026-06-22 16:42:41 -07:00
Ken Sedgwick
ba3681be3c
Merge pull request #319 from ksedgwic/2026-06-signet-support
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
Signet support for the Boltz swapper
2026-06-22 16:26:18 -07:00
Ken Sedgwick
b698844ded
README: document signet Boltz I2P proxy setup
Some checks failed
Code Base Sanity Check / tests (push) Has been cancelled
Code Base Sanity Check / coverage (push) Has been cancelled
Code Base Sanity Check / build-clang (push) Has been cancelled
Add a "Testing on signet with swaps" section to the top-level README describing how
to reach the signet Boltz backend, which has no public clearnet endpoint. Covers
running i2pd's SOCKS5 proxy and a socat forward from 127.0.0.1:8080 to the
service's I2P address (with a systemd unit for persistence), and the
dev-boltz-api BOLTZ_PROXY/BOLTZ_API_BASE environment variables for smoke-testing
the backend directly over I2P.
2026-06-22 16:04:33 -07:00
Ken Sedgwick
8dbde86789
dev-boltz-api.cpp: Support env-var URL/proxy overrides for non-mainnet testing.
The binary was hardcoded to talk to https://boltz.exchange/api via no
proxy, which made it useless for verifying the signet Boltz backend
added by the recent boltz_instances cherry-pick.

Read two new optional environment variables on startup:

  BOLTZ_API_BASE  URL prefix (default: https://boltz.exchange/api)
  BOLTZ_PROXY     libcurl proxy (e.g. socks5h://127.0.0.1:9050)

and pass them through to the Boltz::Connection constructor. No
behavior change when neither variable is set, so existing usage
continues to hit mainnet Boltz.

Tested against signet Boltz via both paths:

  ./dev-boltz-api /getpairs                                # mainnet, default
  BOLTZ_API_BASE=http://127.0.0.1:8080 \
    ./dev-boltz-api /getpairs                              # signet via socat
  BOLTZ_API_BASE=http://boltz7ck...onion \
    BOLTZ_PROXY=socks5h://127.0.0.1:9050 \
    ./dev-boltz-api /getpairs                              # signet direct via Tor
2026-06-13 17:09:04 -07:00
Tamas Jantvik
df0ed1147b
Addition of Boltz backend on signet (clearnet address needs proxy) 2026-06-08 13:28:45 -07:00
Ken Sedgwick
5ecc82c6c4
Update CHANGELOG release date for v0.16.0
Set the v0.16.0 release date to 2026-04-21 in preparation for tagging.
2026-04-21 09:59:04 -07:00
Ken Sedgwick
4a248a1ce9
update CHANGELOG for v0.16.0-rc4 2026-03-24 10:07:42 -07:00
Ken Sedgwick
4a967428d4
Merge pull request #311 from ksedgwic/2026-03-fix-dns-seed-srv-filter
Fix DNS seed parser crash on non-SRV records (#309)
2026-03-24 10:04:51 -07:00
Ken Sedgwick
5a6b5eabe1
Remove defunct DNS seed entries (#309)
Both Lightning DNS seeds are no longer operational: lseed.bitcoinstats.com
returns SERVFAIL and lseed.darosior.ninja is confirmed dead by its
maintainer. The empty seed list is handled gracefully with a warning
log. Retained the original IRC discussion as historical context for future seed
selection.
2026-03-23 14:27:21 -07:00
Ken Sedgwick
592980dd96
Filter parse_dig_srv() for SRV records and catch decode failures (#309)
Normalize tabs to spaces and check that fields[3] == "SRV" before parsing dig
output lines, skipping non-SRV records like SOA that appear in AUTHORITY
sections for defunct DNS seeds. Wrap record parsing in try-catch as
defense-in-depth against malformed records.
2026-03-23 11:21:06 -07:00
Ken Sedgwick
75d4fd36b0
Add test cases for DNS seed parser crash on SOA records (#309)
Add SOA-only and mixed SRV/SOA test inputs to test_parse_dig_srv to reproduce
the crash from issue #309. Both tests currently fail as expected —
parse_dig_srv() passes SOA record fields to decode_bech32_node() which throws
"Not a bech32 string: 3600".
2026-03-23 11:06:27 -07:00
Ken Sedgwick
95d195f8ba
update CHANGELOG for v0.16.0-rc3 2026-03-04 11:32:26 -08:00
clboss-contributor
4057154967 feat: add clang C++20 build job to CI
Add clang build configuration to catch C++20 compatibility issues early.

Changes:
- Add build-clang job to .github/workflows/build.yml
- Add missing #include<cstdint> for std::uint* types (clang strict mode)
- Add -lexecinfo for FreeBSD in configure.ac (backtrace_symbols)
- Fix pessimizing-move warning in test_earningsrebalancer.cpp
- Fix CHANGELOG.md formatting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-04 11:24:31 -08:00
Ken Sedgwick
d90ca280ef
fix: initialize ReservoirSampler::wsum to silence build warning
GCC's deeper inlining at -O2 detects that wsum may be used uninitialized when
ReservoirSampler::add() is inlined into JitRebalancer. Debug builds (-Og) don't
trigger this because GCC doesn't inline deeply enough. The value is overwritten
on the first add() call, so this is purely to satisfy the compiler.
2026-03-04 11:10:33 -08:00
Ken Sedgwick
a17b83ce2d
fix CHANGELOG 2026-03-02 12:19:03 -08:00
Ken Sedgwick
47758cd7f1
Merge pull request #306 from ksedgwic/2026-03-v0.16.0-rc1
Create v0.16.0 rc1
2026-03-02 12:00:51 -08:00
Ken Sedgwick
b64180b4d6
update the release in configure.ac 2026-03-02 11:57:39 -08:00
Ken Sedgwick
6d4a99c86c
update CHANGELOG for v0.16.0 release 2026-03-02 11:57:35 -08:00
Ken Sedgwick
9b9d876c17
fix ignore of pycache stuff 2026-03-02 10:54:20 -08:00
Ken Sedgwick
b1ce639c75
Merge pull request #305 from lduchosal/fix/cpp20-compatibility
Fix: Replace std::result_of with std::invoke_result_t for C++20
2026-03-02 10:29:38 -08:00
clboss-contributor
38bba65ca9 Fix: Replace std::result_of with std::invoke_result_t for C++20
std::result_of was deprecated in C++17 and removed in C++20.
This patch replaces it with std::invoke_result_t which is the
modern equivalent.

Fixes build on systems with C++20 compilers (e.g., FreeBSD 14+
with clang 18).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-01 08:56:16 +01:00
Ken Sedgwick
401bbb79c9
Merge pull request #296 from ksedgwic/2026-02-add-fee-monitor
Add Fee Monitor to Record Per-Channel Stats
2026-02-27 14:46:22 -08:00
Ken Sedgwick
f04dce6f27
contrib: use clboss-feemon-peers to make aggregate plots 2026-02-27 14:29:00 -08:00
Ken Sedgwick
c4be10d63b
feemon: add clboss-feemon-peers to determine peer set for time window 2026-02-27 14:28:59 -08:00
Ken Sedgwick
dcad8df7dc
contrib: increase feemon-validate timestamp tolerance 2026-02-27 14:28:59 -08:00
Ken Sedgwick
d7e20bd58f
contrib: default plot-fees/plot-aggregate to API-only, keep legacy DB optional 2026-02-27 14:28:58 -08:00
Ken Sedgwick
810f14dd0d
contrib/plot-fees: overlay API theory_center on theory plot when available 2026-02-27 14:28:57 -08:00
Ken Sedgwick
5b6416960d
contrib: unify feemon data loading and prefer API over legacy DB in plots 2026-02-27 14:28:56 -08:00
Ken Sedgwick
0aedf04310
contrib: improve feemon-validate 2026-02-27 14:28:56 -08:00