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.
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.
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.
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).
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.
- --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.
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.
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.
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.
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
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.
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.
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".
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.
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>
- plot-size-price: show the price theory level as a function of size_ratio
- plot-balance-price: show the price theory level as a function of balance_ratio
- plot-size-balance: show the price theory level against both size and balance ratios