Commit graph

12 commits

Author SHA1 Message Date
Ken Sedgwick
13a547d3a4
ActiveProber: feed inform=unconstrained on probe success
The previous commit fed only the FAILURE side: probes that hit
WIRE_TEMPORARY_CHANNEL_FAILURE etc. wrote constraints into the
clboss layer.  Successful probes (id1 returned
WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS, the expected
outcome) returned bool=true and did not touch the layer.

This commit adds the symmetric positive feed: when a probe
succeeds, call askrene-inform-channel inform=succeeded on
chan1 (peer's outgoing channel to id1) at amount1.  askrene
treats this as a raised lower-bound on the directed channel's
capacity estimate, so future getroutes calls assign chan1 a
higher success-probability score.

Why this is the dominant signal source in practice:

  Failures are stochastic and bounded (one channel-or-node can
  only fail a few times before askrene routes around it
  entirely).  Successes are repeated -- the same chan1 can
  push the same amount1 many times, raising the lower bound
  monotonically.  Over a day of probes, the success-feed
  contribution to the layer's expected-flow estimate
  vastly exceeds the failure-feed contribution.

Symmetric with the failure path on which channels we feed:

  Only chan1 (peer's outbound to id1) is fed.  chan0 (our
  outbound to peer) is deliberately skipped on the success
  path for the same reason it is skipped on the failure path:
  CLBOSS already has authoritative knowledge of local channel
  state via listpeerchannels, and the shared askrene layer
  exists for cross-subsystem knowledge that is not already
  authoritatively available locally.

No new RPC types, no new error paths.  Boss::Mod::AskreneLayer::
inform_channel_succeeded was already added in the earlier
shared-helpers refactor commit anticipating exactly this use.
2026-05-22 10:52:10 -07:00
Ken Sedgwick
ba8ea5d0ba
ActiveProber: feed sendpay failures into the clboss askrene layer
When a 2-hop probe sendpay fails, parse the waitsendpay error and
record real route failures into the persistent clboss askrene
layer via Boss::Mod::AskreneLayer's shared helpers.  Future
getroutes calls (FundsMover's rebalances, ActiveProber's own
subsequent probes, anything else that consumes the clboss layer)
automatically steer around the failed channel or node.

The PR2 commit introduced the layer + the inform-channel /
disable-node call shape, but FundsMover is the only writer
today, and its writes are gated behind real sendpay attempts
that rarely fire (fees on small rebalance amounts almost always
exceed the prorated budget, so FundsMover gives up
pre-sendpay).  Net result: the layer is essentially empty in
production.

ActiveProber, by contrast, runs on a timer and sends real
sendpays without a budget filter.  Wiring its failure path to
the layer turns it into the dominant feeder, making the layer
infrastructure observable and useful.

Probe-outcome discrimination -- the failure interpretation is
necessarily tighter than FundsMover's because every probe is
designed to fail at the final hop:

  failcode 0x400F (WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS)
                   -> id1 received the HTLC and rejected it
                      because our bit-flipped random
                      payment_hash matches no invoice.  This is
                      the EXPECTED outcome: the route was
                      viable all the way to id1.  Probe
                      success; no layer write.

  code 202 (unparsable onion)
                   -> cannot pin the failure to a specific
                      channel or node.  On a 2-hop route, id1
                      is the most likely culprit; disable_node(id1).

  echan == chan0   -> our outgoing channel had the issue.  Skip
                      the layer write: CLBOSS already has
                      authoritative knowledge of local channel
                      state via listpeerchannels, and the
                      shared layer is for inter-subsystem
                      knowledge that isn't already authoritatively
                      available.

  failcode & 0x2000 (NODE-level)
                   -> disable_node(erring_node).

  channel-level failcode on chan1
                   -> inform_channel_constrained(chan1, dir1, amount1).

  unparseable error data
                   -> swallow; don't guess.

No change to the existing probe-success accounting: the bool
returned by the catching handler still flows into the same
delpay-status / "Finished probing peer X" logic.  The only new
behavior is the side-effect layer write inside record_failure.

Open question, deliberately not addressed here: should
ActiveProber ALSO feed inform=succeeded on probe success
(raising lower-bound estimates on chan1)?  The DEVSTATE
ACTIVE-PROBER-LAYER-FEEDER-2026-05-20 recommends yes, ~5 lines
extra; defer until empirical signet observation shows whether
the failure-feedback alone is enough to drive observable
routing improvements.
2026-05-22 10:52:10 -07:00
Ken Sedgwick
d212080148
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-05-22 09:24:59 -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