Commit graph

12 commits

Author SHA1 Message Date
Ken Sedgwick
6af2e39752
Require the CLN v26.06 getroutes fields; refuse to start on older CLN
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 pre-v26.06 getroutes compatibility fallback read the deprecated
per-hop fields (next_node_id / amount_msat / delay), whose values CLN
defines as the in-side of each hop -- one hop shifted from the
out-side values (node_id_out / amount_out_msat / cltv_out, shipped in
v26.06) that sendpay routes must be built from.  On stock CLN
v24.11..v26.04 the fallback therefore built mispriced routes: small
overpays on the routes that survived, spurious FEE_INSUFFICIENT /
INCORRECT_CLTV_EXPIRY failures on the rest, and -- worst -- those
failures hard-excluded healthy channels in the persistent
failure-learning layer for hours, compounding across restarts.

Drop the fallback entirely and enforce the requirement twice:

- Initiator gains a CLN version gate, ordered before the database and
  signer steps so a refusal leaves no on-disk trace: a getinfo
  version older than v26.06 logs a detailed Error and aborts.  The
  new clboss-skip-cln-version-check flag bypasses the gate for
  operators whose older CLN carries a backport of the v26.06
  getroutes fields (the version string alone cannot show that); an
  unparseable version string warns and proceeds rather than locking
  out custom builds.

- The three getroutes parse sites (FundsMover/Attempter,
  ActiveProber, ChannelCandidateMatchmaker) verify the new fields on
  every response and fail the attempt with a clear Error if absent,
  so a mistakenly bypassed gate degrades into loud per-attempt
  failures rather than shifted routes.

CHANGELOG.md gains a prominent BREAKING entry; README documents the
requirement and the escape hatch.  Users on older CLN releases stay
on CLBOSS 0.16.x, which uses the legacy getroute/pay APIs those
versions still provide.
2026-08-04 11:01:56 -07:00
Ken Sedgwick
a2296177ba
Dowser, ActiveProber: restore self-exclusion via a shared clboss-self layer
The getroute -> getroutes migrations dropped the legacy
exclude=[self_id] argument in the two probing modules whose askrene
source is a remote node.  Nothing replaced it: askrene's gossmap
includes our public channels like anyone else's, and an empty layers
array applies no exclusions.  Consequences:

- Dowser capacity probes could route part of the candidate->patron
  flow through our own node, counting our own liquidity toward a
  candidate's capacity -- retaining weak candidates and over-sizing
  the channels ChannelCreator opens.

- ActiveProber probes could pick path[0] = peer->us, degenerating
  into a circular us->peer->us payment that measures our own shared
  channel's peer->us balance instead of the peer's outward reach,
  with SendpayResultMonitor crediting the peer destination_reached
  for it.

Introduce AskreneLayer::self_layer_name ("clboss-self"): a tiny
persistent layer whose only content is our node in disabled_nodes,
maintained by AskreneLayer::ensure_self_layer() (idempotent create,
deduped disable).  Both modules resolve it before probing and name it
in their getroutes layers array; when askrene is unavailable they
probe without it, as before.  Kept separate from the clboss layer --
whose disabled_nodes also carries self -- because that layer's
learned constraints would bias what the probes measure.
2026-08-04 11:01:55 -07:00
Ken Sedgwick
3fad9db82e
Matchmaker, ActiveProber: migrate getroute -> getroutes for CLN v26.06 compat
Continuation of the v26.06 migration started in the Dowser
commit.  Two more getroute call sites:
ChannelCandidateMatchmaker.cpp and ActiveProber.cpp.  Both use
maxparts=1 since each wants a single route, not a flow estimate.

ActiveProber probes the local node's own outbound liquidity, so
it uses layers=["auto.localchans","auto.sourcefree"] per the
standardized recipe.  Matchmaker probes from a remote source
(a candidate patron) to a remote target, so it passes an empty
layers array -- auto.localchans would inject our private local
channels into a foreign source, and auto.sourcefree would zero
out the source's outgoing fees, either of which could make
askrene pick a patron the proposal cannot actually reach via
public topology.  maxfee_msat is 1% of the probe amount in both
cases.

Matchmaker is a near-clean swap.  The patron id (route[0].id in
the old getroute shape) is read from routes[0].path[0] in the
new getroutes shape; at the parse site we bridge the v26.06+
name (node_id_out) with its deprecated pre-v26.06 predecessor
(next_node_id) via has()/ternary, so the code works on either
CLN flavor.

ActiveProber is more involved.  The previous code stashed
res["route"] as a Jsmn::Object and later appended hops from it
directly into the sendpay route parameter, relying on the fact
that the old getroute hop shape (id/channel/direction/
amount_msat/delay/style) was already sendpay-compatible.  The
new getroutes path[] shape is NOT directly sendpay-compatible
(different field names, short_channel_id_dir encodes scid and
direction together), so we now extract path[0] into typed
values (id1, chan1, direction1, amount1, delay1) and rebuild
the sendpay hop1 explicitly from those.  The Jsmn::Object route
member is dropped.  The hop-field reads in ActiveProber bridge
between v26.06+ (node_id_out / amount_out_msat / cltv_out) and
the deprecated pre-v26.06 names (next_node_id / amount_msat /
delay) via the same has()/ternary pattern.

short_channel_id_dir splits on '/' with an explicit npos check;
a missing slash throws Jsmn::TypeError so the surrounding parse-
error log path catches it cleanly.  Without the check,
sdir.substr(0, npos) and sdir.substr(npos + 1) would feed
malformed input into Ln::Scid (which throws
std::invalid_argument, not caught by the Jsmn::TypeError
handler) or into std::stoul (silently producing a wrong
direction).

ActiveProber also drops its vestigial exclude=[self_id]
parameter: askrene's source/destination model naturally excludes
self when source != self, which is always the case here (the
probe always flows from peer outward, never back through us).

Three of the four getroute call sites in CLBOSS are now on
getroutes; the fourth (FundsMover/Attempter) is deferred to PR2
because its exclude-vector pattern encodes failure feedback from
real payment attempts and warrants a redesign around
askrene-inform-channel rather than a mechanical port.
2026-08-04 11:01:40 -07:00
Ken Sedgwick
dec8114cdf Convert some listpeers uses to listpeerchannels.
A couple `listpeers` uses can remain because they don't need channel
information.  Others use ListpeersAnnouncer and are covered by the
next commit.
2024-06-02 16:19:56 -07:00
Ken Sedgwick
0c9ec733d0 Convert deprecated "msatoshi" fields to "amount_msat"
The type of the value also changes from string to integer.

Was seeing "unknown parameter: msatoshi" in the log ...
2024-04-05 12:48:08 -07:00
Ken Sedgwick
60c07a7d66 Handle JSON-RPC msat amounts in either the old or new conventions 2023-08-18 20:29:21 -07:00
ZmnSCPxj jxPCSnmZ
80b332615b Boss/Mod/ActiveProber.cpp: Truncate path to probe with to 2 hops. 2021-05-10 15:26:03 +08:00
ZmnSCPxj jxPCSnmZ
90ef0a752e Boss/Mod/ActiveProber.cpp: Also auto-delete ActiveProber payments. 2021-04-28 22:59:04 +08:00
ZmnSCPxj jxPCSnmZ
a9d0ad9b18 Boss/Mod/: Use iterators instead of indexing for Jsmn::Object types.
Closes: #28
2020-11-18 16:46:20 +08:00
ZmnSCPxj jxPCSnmZ
41bd7bc6af *: Silence clang warnings. 2020-11-02 19:02:35 +08:00
ZmnSCPxj jxPCSnmZ
460723a5fb Boss/Mod/ActiveProber.cpp: Make printing of route reports consistent. 2020-10-08 00:24:21 +08:00
ZmnSCPxj jxPCSnmZ
9dc12b6068 Boss/Mod/ActiveProber.cpp: active probing module. 2020-10-07 15:06:38 +08:00