Commit graph

9 commits

Author SHA1 Message Date
Ken Sedgwick
17ba012f9b
AskreneLayer: extract shared helpers for clboss layer writes
Move the askrene-inform-channel and askrene-disable-node helpers
from Boss::Mod::FundsMover::Attempter::Impl (where they were
private member functions) into a new shared module
Boss::Mod::AskreneLayer.  Lift the "clboss" layer name from a
FundsMover-local constant into a shared constant.

Pure refactor, no behavioral change.  Existing tests still
pass (79/79).  Done now because PR4 (ActiveProber feeding the
same layer) will be the second producer; sharing avoids
duplicating the JSON construction, the layer-name string, and
the silent-RpcError-catch logic.

The new module exposes three free functions:

- inform_channel_constrained(rpc, layer, scid, dir, amount):
  same shape and semantics as Attempter's prior private method.
- inform_channel_succeeded(rpc, layer, scid, dir, amount): new
  variant emitting inform=succeeded instead of inform=constrained.
  Not used by FundsMover (sendpay failures only carry negative
  signals).  Added in this commit because the implementation is
  one line over the shared internal helper, and PR4's
  open-question may have ActiveProber call it on probe-success
  to record positive lower-bound observations on probed
  channels.
- disable_node(rpc, layer, node_id): same shape and semantics as
  Attempter's prior private method.

All three functions silently swallow RpcError, matching the
prior behavior in Attempter.  The rationale: if the layer is
unavailable (e.g. CLN < v24.11 where askrene layers do not
exist), the call gracefully degrades to no-op rather than
crashing the caller.  Better degraded learning than crashed
plugin.

The layer name "clboss" follows the xpay convention:
persistent shared-knowledge layer = owning plugin name.  All
CLBOSS-internal writers (FundsMover today, ActiveProber in
PR4, possibly others later) target the same single layer so
the accumulated knowledge benefits every downstream getroutes
call.
2026-05-22 10:52:09 -07:00
Ken Sedgwick
c4be795de7
FundsMover: migrate to getroutes + askrene-inform-channel learning
The fourth and final getroute call site in CLBOSS, deferred from
the v26.06 compatibility PR because its exclude-vector pattern
encoded failure feedback from real payment attempts and needed a
design step rather than a mechanical port.

Old behavior: getroute with an accumulated excludes vector,
listchannels per first-hop to compute the source's outgoing fees,
local fee-budget check, on failure parse the onion error and
push the failing channel-or-node into excludes, retry; if fees
exceeded the prorated budget, decrement a "fuzzpercent" knob and
retry the routing call hoping for a cheaper path.

New behavior: a single persistent askrene layer named "clboss"
holds CLBOSS's accumulated failure feedback as either
channel-capacity constraints (askrene-inform-channel inform=
constrained) or node-level exclusions (askrene-disable-node);
getroutes consumes that layer alongside auto.localchans and
auto.sourcefree, with our prorated fee budget (minus the
destination's last-hop fee, which is a fixed cost we know up
front) passed as maxfee_msat so askrene either returns a route
within budget or fails cleanly with error 206.  When a sendpay
fails along the route, the onion error's erring_channel or
erring_node is recorded into the layer; the next getroutes call
automatically routes around it, both for this Attempter run and
for every subsequent CLBOSS attempt (and eventually for any
other CLBOSS subsystem that consumes the same layer).

getroutes does not accept a per-call exclude parameter -- askrene
exclusions are layer-resident.  We could use a transient
per-payment layer (xpay's pattern for routehints), but the
failure knowledge we record here is durably useful across runs:
a channel that ran out of liquidity at amount X will likely fail
again at amount X soon.  Recording into a persistent layer lets
future calls -- including this run's own retries, future
FundsMover attempts, and other CLBOSS subsystems if we migrate
them -- benefit automatically.

The layer is named "clboss" (xpay's convention: persistent
shared-knowledge layer = plugin name) and is created idempotently
at startup with persistent=true.  Idempotent create-layer means
the second and subsequent CLBOSS startups silently succeed.  If
create-layer fails (e.g. CLN < v24.11 where it does not exist),
inform-channel and disable-node calls will also fail; both are
caught and silently swallowed -- the failure mode is degraded
learning, not crashed Attempter.

getroutes' path[] hop fields were renamed in v26.06: the new
names (node_id_out, amount_in_msat, amount_out_msat, cltv_in,
cltv_out) coexist alongside the deprecated old names
(next_node_id, amount_msat, delay) through v27.06.  This commit
bridges the two at the parse site via has()/ternary: prefer the
new name, fall back to the old.  The bridge is necessary because
v26.06+ in developer mode (or allow-deprecated-apis=false)
suppresses the deprecated names entirely, while CLN v26.04 emits
only those.  The TODO at the parse site flags the migration that
will be needed before v27.06 retires the deprecated names.

Of the new field set, amount_in_msat and cltv_in are v26.06-only
with no equivalent on the deprecated shape.  The bridge handles
the OUT-side fields (amount_out_msat <-> amount_msat, cltv_out
<-> delay) -- the amount and CLTV travelling downstream from
each hop, which is what sendpay needs.  But the IN-side
shortcuts that would let us recover the source's outgoing-channel
fees from path[0] alone (source_amount = path[0].amount_in_msat,
source_delay = path[0].cltv_in) cannot be polyfilled on v26.04.
compute_source_amount() therefore retains a listchannels round-
trip to read the source's outgoing-channel fees and derive
source_amount / source_delay from path[0].amount_out_msat /
path[0].cltv_out.  Once v26.04 is no longer supported, the
listchannels read can be dropped in favor of direct
path[0].amount_in_msat / path[0].cltv_in reads.

short_channel_id_dir is parsed with an explicit npos check on
the '/' position; a missing slash throws Jsmn::TypeError so the
existing "Unexpected getroutes response" 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).

- fuzzpercent ladder is gone.  Askrene's probability-based cost
  model with maxfee_msat captures the same "look for a cheaper
  route" intent directly; if no route fits the budget the call
  fails with 206 and we give up cleanly.

- The Jsmn::Object route member is replaced with a typed
  std::vector<Hop>.  Each Hop holds (id, scid, direction,
  amount_msat, delay) translated from the path[] response,
  ready to be spliced into sendpay's route shape in
  make_route().

- The "Failed at source" / "Failed at destination" early-return
  semantics on onion code 204.
- The random-middle-hop fallback for unparsable onions (code
  202).  Now uses askrene-disable-node instead of pushing into
  the local excludes vector.
- The fee budget bookkeeping (deduct optimistically, refund on
  sendpay failure).
- The listchannels round-trip for source-side computation
  (necessary until path[0].amount_in_msat is universally
  available; see note above).
- All other Attempter logic: claim handling, label generation,
  preimage flow, sendpay/waitsendpay/delpay sequencing.

v24.11 -- when askrene-create-layer, askrene-inform-channel,
askrene-disable-node, persistent layer support, and the
short_channel_id_dir field in getroutes' path[] all landed.  On
older CLN versions FundsMover will silently fall through to
degraded behavior (no failure-feedback layer, getroutes parse
fails), but route discovery and basic operation in other CLBOSS
subsystems continue.
2026-05-22 10:52:07 -07:00
ZmnSCPxj jxPCSnmZ
f36ecd5300 Boss/Mod/FundsMover/Main.cpp: Block and log an error if something tries to move from or to an unmanaged node. 2022-05-11 12:09:13 +00:00
ZmnSCPxj jxPCSnmZ
03c0bd2b34 Boss/Mod/*: Fix pedantic warnings from clang. 2021-05-02 16:41:09 +08:00
ZmnSCPxj jxPCSnmZ
cff94ce785 Boss/Mod/FundsMover/*: Use general module for cleaning up payments. 2021-04-28 19:12:34 +08:00
ZmnSCPxj jxPCSnmZ
478b77b6d4 Boss/Mod/FundsMover/Main.cpp: Tone down payment removal. 2020-11-12 09:36:23 +08:00
ZmnSCPxj jxPCSnmZ
0a078a6f11 Boss/Mod/FundsMover/Main.cpp: Avoid running multiple delpay threads. 2020-11-12 09:25:19 +08:00
ZmnSCPxj jxPCSnmZ
7e068431ff Boss/Mod/FundsMover/PaymentDeleter.cpp: Delete our FundsMover payments periodically. 2020-11-11 15:14:08 +08:00
ZmnSCPxj jxPCSnmZ
7a9fe45655 Boss/Mod/FundsMover/Main.cpp: Finish packaging up funds mover module. 2020-10-22 08:48:09 +08:00