Commit Graph

150 Commits

Author SHA1 Message Date
Lagrang3
0c5c7a5334 askrene: add maxparts
Changelog-Added: askrene: add a new parameter maxparts to getroutes that limits the number of routes in the solution.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-15 16:13:19 +09:30
Lagrang3
b298e3fc97 askrene: refine: add helper function remove_flows
remove_flows is a helper function to remove flows from a set so that we
keep the number of flows limited.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-15 16:13:19 +09:30
Lagrang3
5b8102ec32 askrene: paranoid checks ...
that new flows respect the HTLC min/max constraints.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
f7ba8f1ca9 askrene: refine: remove refine_with_fee_and_limits
and remove unused helper functions.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
767893de7a askrene: rework the caller of the MCF solver
We use a wrapper around the MCF solver that takes care of finding the
best linearization parameters and fixing the flow values to meet the
htlc_min and htlc_max constraints.
We have reworked the current implementation and made it a bit more
similar to renepay's version.

Out of 50000 simulated payment situations distributed accross payment
amounts of 1e2, 1e3, 1e4, 1e5 and 1e6 sats, we find that 133 failed
cases in the master branch turn to success with the current changes,
while only 3 success cases in the master are not solved by the changes.

                master
            +-------+------+
            | S     | F    |
        +---+-------+------+
        | S | 46329 | 133  |
changes +---+-------+------+
        | F | 3     | 3535 |
        +---+-------+------+

Out of the 133 cases that flipped from failure to success the failed
reasons were:

122 -> "Could not find route without excessive cost"
5   -> "We couldn't quite afford it"
5   -> "Amount *msat below minimum"
1   -> tripped an HTLC min check

Changelog-None.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
d64f438bc2 askrene: refine: add a step to increase flows ...
by a small amount if the deliver amount is less than the requested
amount by X.
This step saves runtime by avoiding calling an extra MCF
and it helps us solve a small percentage of cases where the only
available routes have HTLCmin that is bigger than X.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
3a0d0da5ce askrene: refine: expose some of the refine API
that can be useful for us in the mcf.c main loop.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
b479963c09 askrene: refine: disable HTLC min violations
Disable channels with HTLC min violations so that we don't hit them
twice when computing routes.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
f4f8ea08ff askrene: refine: remove flows with HTLC min faults
Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
620b96a38b askrene: add new functions to refine flows
Try a new way to refine flows,
ie. reduce excess due to MCF accuracy and HTLC max constraints
after hop amounts are computed with fees included.

Changelog-None.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-08-08 14:07:51 +09:30
Lagrang3
420cff9350 askrene: mcf: trade granularity for performance
Speed in getroutes up by setting the granularity to 1000

Amount (sats) | speedup
-----------------------
          100 | 1.00
         1000 | 1.00
        10000 | 1.06
       100000 | 1.31
      1000000 | 2.64

Worst runtime of getroutes

Amount (sats) | before (ms) | after (ms)
--------------------------------------
          100 | 1507        | 761
         1000 | 2129        | 1214
        10000 | 1632        | 1043
       100000 | 2004        | 1150
      1000000 | 27170       | 3289

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-19 10:09:17 +09:30
Lagrang3
b7f3d7bcc4 askrene: prune un-used arcs
From the multiple arcs that derive from the same channel we consider
only those with the smallest cost such that the payment amount and HTLC
max can fit in their combined capacity, ie. we prune high cost arcs that
surely will never be used by the optimal solution.

This reduces the number of arcs in the graph approximately from 8 arcs
per channel to approximately 2 arcs per channel.

No pruning.
amount:		100 	1000 	10000 	100000 	1000000
channels:	104741	106163	106607	106654	106666
arcs:		837928	849304	852856	853232	853328

Prune, limit the channel capacity by its HTLC max
amount:		100 	1000 	10000 	100000 	1000000
channels:	104741	106163	106607	106654	106666
arcs:		255502	259314	260538	260676	260704

Prune, limit the channel capacity to the payment amount
amount:		100 	1000 	10000 	100000 	1000000
channels:	104741	106163	106607	106654	106666
arcs:		209482	216270	228618	295450	432468

Prune, limit the channel capacity to the payment amount and its HTLC max
amount:		100 	1000 	10000 	100000 	1000000
channels:	104741	106163	106607	106654	106666
arcs:		209480	212324	213242	215726	228018

This produces a slight speedup for MCF computations:

Amount (sats) | speedup
-----------------------
          100 | 1.89
         1000 | 1.77
        10000 | 1.25
       100000 | 1.25
      1000000 | 1.18

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-19 10:09:17 +09:30
Lagrang3
25c88447fa askrene: add algorithm for single path routing
Changelog-Added: askrene: an optimal single-path solver has been added, it can be called using the developer option --dev_algorithm=single-path or by adding the layer "auto.no_mpp_support"

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-18 15:13:41 +09:30
Lagrang3
47b0f67d04 askrene: add internal API for single-path routes
The single path solver uses the same probability cost and fee cost
estimation of minflow. Single path routes computed this way are
suboptimal with respect to the MCF solution but still are optimal among
any other single path. Computationally is way faster than MCF, therefore
for some trivial payments it should be prefered.

Changelog-None.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-18 15:13:41 +09:30
Lagrang3
2a6eab2843 askrene: refactor MCF
Refactor MCF solver: remove structs linear_network and residual_network.
Prefer passing raw data to the helper functions.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-18 15:13:41 +09:30
Lagrang3
34cf3334f8 askrene: add a dev parameter to switch algorithm
Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-11 12:14:45 +09:30
Rusty Russell
4500818312 askrene: fix up getroutes_info struct.
It was originally a wrapper for JSON param() results, but now it's a more
generic struct.  So make it clear that the fields are not optional.  This
means a manual assignment in the initial population of this struct, but
all the users are now far clearer.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-07-11 12:14:45 +09:30
Rusty Russell
2a5239589e askrene: move get_routes into do_getroutes.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-07-11 12:14:45 +09:30
Rusty Russell
71525173a0 askrene: extract getroutes json formatting function.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-07-11 12:14:45 +09:30
Rusty Russell
98e30f2c42 askrene: extracet convert_flows_to_routes into its own function.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-07-11 12:14:45 +09:30
Rusty Russell
2a8334b06e plugins/askrene: extract apply_layers into its own function.
Simple refactoring.

Stolen entirely from Eduardo.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-07-11 12:14:45 +09:30
Rusty Russell
f1fa498663 askrene: houst struct getroutes_info higher to clarify following patches.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-07-11 12:14:45 +09:30
Lagrang3
88bb1636bc askrene: refactor get_routes ...
Move the feature tuning algorithm to mcf.c, ie. the loops for searching
a good mu and delay_feefactor to satisfy the problem constraints.

We are looking to set the stage for an execution logic that allows for
multiple choices of routing algorithms, mainly for experimenting without
breaking the default working code.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-11 12:14:45 +09:30
Lagrang3
266a5f9e85 askrene: add runtime of getroutes to the logs
Add log information about the runtime of getroutes.

Changelog-None: askrene: add runtime of getroutes to the logs

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-07-10 23:37:06 +09:30
Lagrang3
81417958d4 askrene-inform-channel: change order of operations
Change order of operations to ensure that askrene-inform-channel with
inform=constrained computes the correct upper bound on the liquidity:

    upperBound = reserves + amount - 1

With the previous order of operations in the case amount=0 we would get:

    upperBound = reserves

instead of
    upperBound = reserves - 1

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-05-13 19:14:57 +09:30
Rusty Russell
9ce3f5dde4 askrene: fix API breakage, add tests.
We cannot add new parameters in the middle, since we accept parameters by JSON
array as well as by dicts.  In fact, this broke tests, but due to unrelated
breakage in the GitHub "Automerge" functionality, it got applied as
556e38c838 ("askrene-bias-channel: bias call add
up.").

Also add tests, and a better Changelog line.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: JSON-RPC: `askrene-bias-channel` now has a `relative` option to add, rather than replace, a channel bias.
2025-05-11 11:25:40 +09:30
Lagrang3
556e38c838 askrene-bias-channel: bias call add up.
The channel bias feature is not being used yet by any plugin, so this
hopefully doesn't break any working code.
When askrene-bias-channel is called the bias quantity is added on top of
any previous biased already present on that channel instead of
overwriting it.

Changelog-Changed: askrene-bias-channel: bias call add up.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-05-08 12:28:57 +09:30
Lagrang3
47babbf661 askrene: add LOG_TRACE to every rpc entry point
This could be helpful for debugging the interaction of renepay/xpay with
askrene.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-05-02 13:59:13 -07:00
Lagrang3
35f899a588 fetch max total htlc value from listpeerchannel
The parameter max_htlc_value_in_flight_msat stablished by peers on
channel opening (BOLT02) can now be retrived from the
gossmods_from_listpeerchannels API.

Adapted the corresponding callback functions in renepay and askrene to
take into account that value as a constraint to the value we can send
through a channel.

Changelog-Add: fetch max_htlc_value_in_flight_msat from gossmods_listpeerchannels API

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-02-21 17:03:36 -06:00
Rusty Russell
461eb2eddb askrene: remove all small channels if there's no MPP support.
This is an inefficient hack.  Can you tell I really didn't want to
implement this?  MPP was finalized in 2018 FFS.

We do this by adding another "auto" layer, which removes all too-small
channels, and then makes our MPP node pile all the funds into the largest
channel it chooses.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-02-14 22:17:21 +10:30
Rusty Russell
91d7394175 askrene: don't include impossible channels in the MCF graph.
In particular, if the total amount we're sending is less than the minimum amount
the channel insists on, we can eliminate it.

This fixes the problem that we're really trying to send a de-minumus
amount (rather than the more obscure case where we divide the amount
and then it is below the minimum).

After trying several other approaches, this was by far the cleanest!

Reported-by: https://github.com/JssDWt
Fixes: https://github.com/ElementsProject/lightning/issues/8045
Changelog-Fixed: xpay: don't simply give up if our total amount is less than htlc_minimum_msat on some channel.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-02-14 15:18:48 +10:30
Rusty Russell
fdfc7ce62f gossmap: add (and use) logging hook.
Default goes to stderr for LOG_UNUSUAL and higher.

We have to whitelist more cases in map_catchup so we don't spam the logs
with perfectly-expected (but ignored) messages though.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-02-11 15:11:47 -06:00
Rusty Russell
e0aaf60bbd askrene: don't crash, just report, when a flow's remaining capacity is negative.
I'm not sure why this happens, and suspect it is caused by an issue elsewhere, so
add some verbose debugging, don't crash.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Fixes: https://github.com/ElementsProject/lightning/issues/8017
2025-01-28 10:53:22 +10:30
Rusty Russell
c31eed433c askrene: expose fmt_flow_full and make more generic.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-01-28 10:53:22 +10:30
Rusty Russell
3387bba9be askrene: don't create 0-msat flow in corner case.
Shouldn't happen, but I can't *prove* it's impossible.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-01-28 10:53:22 +10:30
Rusty Russell
01bce4e7b7 askrene: don't crash if asked to route 0 msat.
But don't allow it either.

```
Jan 19 13:18:52 boltz lightningd[2259911]: cln-askrene: plugins/askrene/algorithm.c:274: simple_feasibleflow: Assertion `amount > 0' failed.
Jan 19 13:18:52 boltz lightningd[2259911]: cln-askrene: FATAL SIGNAL 6 (version v24.11.1-1-ge9dbdeb)
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e212b407 send_backtrace
Jan 19 13:18:52 boltz lightningd[2259911]:         common/daemon.c:33
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e212b49e crashdump
Jan 19 13:18:52 boltz lightningd[2259911]:         common/daemon.c:75
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964ba9251f ???
Jan 19 13:18:52 boltz lightningd[2259911]:         ???:0
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964bae69fc ???
Jan 19 13:18:52 boltz lightningd[2259911]:         ???:0
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964ba92475 ???
Jan 19 13:18:52 boltz lightningd[2259911]:         ???:0
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964ba787f2 ???
Jan 19 13:18:52 boltz lightningd[2259911]:         ???:0
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964ba7871a ???
Jan 19 13:18:52 boltz lightningd[2259911]:         ???:0
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964ba89e95 ???
Jan 19 13:18:52 boltz lightningd[2259911]:         ???:0
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e211695e simple_feasibleflow
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/askrene/algorithm.c:274
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e2111495 minflow
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/askrene/mcf.c:1014
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e210bc74 get_routes
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/askrene/askrene.c:414
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e210c610 do_getroutes
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/askrene/askrene.c:615
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e210cad8 listpeerchannels_done
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/askrene/askrene.c:741
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e211b35a handle_rpc_reply
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/libplugin.c:1084
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e211b54c rpc_read_response_one
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/libplugin.c:1388
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e211b5fd rpc_conn_read_response
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/libplugin.c:1412
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e214fe8f next_plan
Jan 19 13:18:52 boltz lightningd[2259911]:         ccan/ccan/io/io.c:60
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e215036e do_plan
Jan 19 13:18:52 boltz lightningd[2259911]:         ccan/ccan/io/io.c:422
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e215042b io_ready
Jan 19 13:18:52 boltz lightningd[2259911]:         ccan/ccan/io/io.c:439
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e2151e2e io_loop
Jan 19 13:18:52 boltz lightningd[2259911]:         ccan/ccan/io/poll.c:455
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e211cc29 plugin_main
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/libplugin.c:2488
Jan 19 13:18:52 boltz lightningd[2259911]: 0x5576e210cb38 main
Jan 19 13:18:52 boltz lightningd[2259911]:         plugins/askrene/askrene.c:1262
Jan 19 13:18:52 boltz lightningd[2259911]: 0x7f964ba79d8f ???
```

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: JSON-RPC: `getroutes` will refuse, not crash, if asked to find a route fr 0msat.
2025-01-28 10:53:22 +10:30
michael1011
060368bb0a xpay: add maxdelay parameter
Changelog-Added: Plugins: `xpay` now supports a `maxdelay` parameter for better `xpay-handle-pay` compatibility.
2025-01-22 12:19:47 -08:00
Rusty Russell
b6c1ffa359 ccan/htable: update to explicit DUPS/NODUPS types.
The updated API requires typed htables to explicitly state whether they
allow duplicates: for most cases we don't, but we've had issues in the
past.

This is a big patch, but mainly mechanical.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-01-21 09:18:25 +10:30
Rusty Russell
fba738b65e askrene: really fix race between layer creation and persistent layer loading.
Using jsonrpc_request_sync, layers are loaded before we finish init,
so we never can be asked to create a layer before we've loaded it
(xpay creates a layer immediately on startup).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-None: persistent layers new this release.
2024-11-26 16:04:13 +10:30
Rusty Russell
d256e11108 askrene: reorder functions.
No code changes.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-11-26 16:04:13 +10:30
Rusty Russell
af629e600e askrene: don't re-save layers as we restore them!
Create lower-level versions of routines to create biases, layers,
constraints, etc and only save the ones called from the public APIs.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-None: persistent layers were only added in this release
2024-11-26 16:04:13 +10:30
Lagrang3
05514b46e3 Askrene: change median factor to 1.
The ratio of the median of the fees and probability cost is overall not
a bad factor to combine these two features. This is what the
test_real_data shows.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
2b3fd67dfb askrene: don't skip fee_fallback test
The fee_fallback test would fail after fixing the computation of the
median. Now by we can restore it by making the probability cost factor
1000x higher than the ratio of the median. This shows how hard it is to
combine fee and probability costs and why is the current approach so
fragile.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
9fdcc26d1d askrene: bugfix queue overflow
Changelog-none

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
9966969d4c askrene: remove allocation checks
Rusty: "allocations don't fail"

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
460a28bb32 askrene: add compiler flag ASKRENE_UNITTEST
Rusty: "We don't generally use NDEBUG in our code"

Instead use a compile time flag ASKRENE_UNITTEST to make checks on unit
tests that we don't normally need on release code.

Changelog-none

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
b1cd26373b askrene: small fixes suggested by Rusty Russell
- use graph_max_num_arcs/nodes instead of tal_count in bound checks,
- don't use ccan/lqueue, use instead a minimalistic queue
  implementation with an array,
- add missing const qualifiers to temporary tal allocators,
- check preconditions with assert,
- remove inline specifier for static functions,

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
44c9609f3a askrene: add arbitrary precision flow unit
Changelog-none: askrene: add arbitrary precision flow unit

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
4dc1a44cd9 askrene: fix the median
The calculation of the median values of probability and fee cost in the
linear approximation had a bug by counting on non-existing arcs.

Changelog-none: askrene: fix the median

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30
Lagrang3
ee623616d2 askrene: fix CI
check the return value of scanf in askrene unit tests,

Changelog-none: askrene: fix CI

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2024-11-21 16:17:52 +10:30