199 Commits

Author SHA1 Message Date
Rusty Russell
d5c2c486f1 askrene: close files in child to isolate against bugs.
This makes sure it cannot interfere with the parent askrene's
connection to lightningd, for example.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
6903cf2efb askrene: make "child.c" to be the explicit child entry point.
The fork logic itself is pretty simple, so do that directly in
askrene.c, and then call into "run_child()" almost as soon as
we do the fork.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
3c6504a99e askrene: limit how many children we have.
Queue them before we query local channels, so they don't use stale
information.

Changelog-Added: Config: `askrene-max-threads` to control how many CPUs we use for routing (default 4).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
fb4232dff8 askrene: actually run children in parallel.
Changelog-Changed: Plugins: `askrene` now runs routing in parallel.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
68b30b1e5d askrene: have child make struct route_query internally.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
b002824217 askrene: move route_query definition and functions into child/.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
85c9179f77 askrene: expose additional_costs htable so child can access it.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
0f575ac85a askrene: remove non child-friendly fields from struct route_query.
Notably no access to the struct command and struct plugin.

Note: we actually *do* mess with askrene->reserves, but the previous code
used cmd to get to it.  Now we need to include a non-const pointer in
struct route_query.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
ac9aa975ad askrene: make children use child_log() instead of rq_log.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
33e2f0a47b askrene: move fork() entry point into its own file.
Now there's only one file clearly shared by both parent and child.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
395261fc30 askrene: move fmt_flow_full from askrene.c into flow.c.
Weird that it was in askrene.c

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
8775b62871 askrene: move routines only accessed by the child process into child/.
We want to make it clear when future generations edit the code, which
routines are called in the child (i.e. all the routing), and which in
the parent.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
da2f77767c askrene: add child_log function so child can do logging.
We just shim rq_log for now, but we'll be weaning the child process off
that soon.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
0ede29b81f askrene: fork before calling the route solver.
This is fairly simple.  We do all the prep work, fire off the child,
and it continues all the way to producing JSON output (or an error).
The parent then forwards it.

Limitations (fixed in successive patches):

1. Child logging currently gets lost.
2. We wait for the child, so this code is not a speedup.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
e397b12282 askrene: make minflow() static, and remove unused linear_flow_cost.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Rusty Russell
d9774e73dc bitcoin: hash_scid and hash_scidd public functions.
We reimplemented this redundantly: hash_scid was called
short_channel_id_hash, so I obviously missed it.

Rename, and implement hash_scidd helper too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-02-19 17:04:35 +10:30
Lagrang3
f1bf66c91f askrene: fixed a timeout corner case
Changelog-Fixed: askrene: fixed a class of corner cases that cause askrene main loop to timeout instead of quickly failing, thus wasting runtime.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-02-02 10:23:27 +10:30
Lagrang3
41a5c68aa8 askrene: consider fees during *explain failure*
We would try to explain a failure by simply finding a path between
source and destination and then checking the constraints.
However, we did not add fees.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-02-02 10:23:27 +10:30
Lagrang3
3822a67030 askrene: add auto.include_fees layer
Changelog-Added: askrene: add a new layer auto.include_fees thhat makes fees be deducted from the payment amount making in effect the receiver pay for routing fees.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-01-29 15:20:25 +10:30
Rusty Russell
a3946663ec askrene: speed up when using large number of layers.
Simple bench.

Before:
   Creating 20,000 layers:  20 seconds
   Creating 50,000 layers:  107 seconds

After:
   Creating 20,000 layers:  7 seconds
   Creating 50,000 layers:  15 seconds
   Creating 100,000 layers: 29 seconds

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-01-27 13:59:36 +10:30
Rusty Russell
35e703bfe1 askrene: don't crash if refining flow which has capacity greaater than max it should have.
```
1767724611265   2026-01-06T18:36:51.265Z                plugins/libplugin.c:1073
1767724611265   2026-01-06T18:36:51.265Z        0x55fc0c1428ac handle_rpc_reply
1767724611264   2026-01-06T18:36:51.264Z                plugins/askrene/askrene.c:801
1767724611264   2026-01-06T18:36:51.264Z        0x55fc0c13174c listpeerchannels_done
1767724611264   2026-01-06T18:36:51.264Z                plugins/askrene/askrene.c:669
1767724611264   2026-01-06T18:36:51.264Z        0x55fc0c130f55 do_getroutes
1767724611264   2026-01-06T18:36:51.264Z                plugins/askrene/mcf.c:1636
1767724611264   2026-01-06T18:36:51.264Z        0x55fc0c138bd7 default_routes
1767724611264   2026-01-06T18:36:51.264Z                plugins/askrene/mcf.c:1415
1767724611264   2026-01-06T18:36:51.264Z        0x55fc0c1382ec linear_routes
1767724611264   2026-01-06T18:36:51.264Z                plugins/askrene/refine.c:510
1767724611264   2026-01-06T18:36:51.264Z        0x55fc0c13b110 refine_flows
1767724611264   2026-01-06T18:36:51.264Z                plugins/askrene/refine.c:449
1767724611264   2026-01-06T18:36:51.264Z        0x55fc0c13ac9f increase_flows
1767724611264   2026-01-06T18:36:51.264Z                abort+0xde:0
```

Fixes: #8823
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: plugins: `askrene` can crash on a corner case in increase_flows.
2026-01-14 17:06:02 +10:30
Lagrang3
118e474637 askrene: fix payment crash
Changelog-Fixed: askrene: fix a plugin crash triggered during single path payments when a channel fees doesn't fit u32.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-01-13 15:16:46 +10:30
Rusty Russell
241324aa09 gossipd: don't shortcut dying phase for local channels.
This means that we won't complain to peers which gossip about our
channels, but it does mean that our channel graph (like other nodes on
the network) will show two channels, not one, for the duration.

For this reason, we need askrene to omit local dying channels.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-01-08 22:33:19 +10:30
Rusty Russell
eb83a205b9 askrene: move datastore wire functions into separate file for lightning-downgrade to use.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-28 09:16:53 +10:30
Rusty Russell
1102d8063e askrene: add optional layers to reservations.
We have the issue of aliases: xpay uses scids like 0x0x0 for
routehints and blinded paths, and then can apply reservations to them.  But
generally, reservations are *global*, so we need to differentiate.

Changelog-Added: Plugins: `askrene-reserve` and `askrene-unreserve` can take an optional `layer` inside `path` elements.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 13:52:54 +10:30
Rusty Russell
6e4bc1dd6c askrene: neated flow array handling, by freeing flows we discard.
Pointed out by @Lagrang3; he's right, while it's a temporary leak the
way we use flows, it's still a trap.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
69adf38784 askrene: remove now-unused bottleneck_idx from flow_max_deliverable.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
8c7ac33f88 askrene: implement reduce_num_flows in refine, using increase_flows().
Now we simply call it at the end.  We need to check it hasn't violated fee maxima, but
otherwise it's simple.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Plugins: `askrene` now handles limits on number of htlcs much more gracefully.
2025-11-17 10:56:18 +10:30
Rusty Russell
050b149e53 askrene: handle maxparts parameter values 1 and 0.
For 1, we use single-path.  For 0, reject.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
330f51aad7 askrene: make increase_flows function more generic.
Rewrite it, so it properly takes into account interactions between flows
by using reservations.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
a8a6a44679 askrene: clean up renamed functions.
We added _noidx versions of the sort functions, but now they're the only ones, we can
rename them to the old names.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
7c7a4f8795 askrene: Remove index indirection from squash_flows, simplify sorting.
We don't need to convert to strings, we can compare directly.  This removes the final
use of the index arrays.

This of course changes the order of returned routes, which alters test_real_biases, since
that biases against the final channel in the *first* route.

Took me far too long to diagnose that!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
2735673f82 askrene: make increase_flows() use the raw flows array.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
e3dfc020da askrene: remove indexes from refine_flows except for increase_flows()
This removes the index array from code after increase_flows()m, so we use the flows
array directly.

The next step will be to make increase_flows() use the flows array, and remove the
index array indirection entirely.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
565a92e8fa askrene: use flows array directly in remove_excess.
We don't need the indexes array, we can use this directly.

We still set up the indexes array (for now) after we call this.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
31d28bad86 askrene: remove max_deliverable cache from increase_flows.
Make it calculate on demand.  This will be useful when we call it from elsewhere.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
e120202120 askrene: fix use-after-free if remove_htlc_min_violations fails.
It can only fail on overflow, but if it did, the fail path frees working_ctx
and returns "error_message".

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
b5b4dbf2c2 askrene: fix error path if we fail sanity checks.
We've already freed the working_ctx, and the fail path does that again.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
b6c220457f askrene: remove overzealous cache of channel_data.
This is not worth optimizing that I can see.  Using a non-debug build I get
the following times for tests/test_askrene.py::test_real_data

Before:
	143 seconds

After:
	141 seconds.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
35f65c5d91 common: add amount_msat_deduct / amount_msat_deduct_sub.
I added amount_msat_accumulate for the "a+=b" case, but I was struggling
with a name for the subtractive equivalent.  After some prompting, ChatGPT
suggested deduct.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-17 10:56:18 +10:30
Rusty Russell
8b9020d7b9 global: use clock_time in place of time_now().
Except for tracing, that sticks with time_now().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-13 21:21:29 +10:30
Lagrang3
4f1c8806d7 askrene: add askrene-bias-node rpc
Changelog-Added: askrene-bias-node: an RPC command to set a bias on node's outgoing or incoming channels.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-11-13 15:15:27 +10:30
Lagrang3
5769beb1db askrene: add timestamp to biases
We add one more field to biases: "timestamp".
With the timestamp variable old biases can be removed with the
askrene-age command.

Changelog-Added: Plugins: askrene channel biases now have an associated timestamp, and are timed out by askrene-age

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2025-11-13 15:15:27 +10:30
Rusty Russell
07c57b6015 askrene: implement 10-second deadline.
We have another report of looping.  This maxparts code is being completely
rewritten, but it's good to have a catchall for any other cases which might
emerge.

I had to make it customizable since our tests under valgrind are SLOW!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-03 12:54:37 +10:30
Rusty Russell
03d38b612d askrene: fix infinite loop if refine_flows() cuts down our last flow with 1 remaining before maxparts.
1. We would find a flow.
2. refine_flow would reduce it so it doesn't deliver enough.
3. So we need to find another, but we are at the limit.
4. So we remove the flow we found.
5. Goto 1.

This can be fixed by disabling a channel which we caused us to reduce the flow,
so we should always make forward progress.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Plugins: `askrene` could enter an infinite loop when maxparts is restricted.
2025-11-03 12:54:37 +10:30
Rusty Russell
75616f6b77 common: add new_htable() macro to allocate, initialize and setup memleak coverage for any typed hash table.
You can now simply add per-tal-object helpers for memleak, but our older pattern required
calling memleak functions explicitly during memleak handling.  Hash tables in particular need
to be dynamically allocated (we override the allocators using htable_set_allocator and assume
this), so it makes sense to have a helper macro that does all three.

This eliminates a huge amount of code.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-10-24 11:30:17 +10:30
Rusty Russell
f6a4e79420 global: remove unnecessary includes from headers.
Each header should only include the other headers it needs to compile;
`devtools/reduce-includes.sh */*.h` does this.  The C files then need
additional includes if they don't compile.

And remove the entirely useless wire/onion_wire.h, which only serves to include wire/onion_wiregen.h.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-10-23 06:44:04 +10:30
Rusty Russell
65d997842e Makefiles: remove redundant dependencies, and have objects depend on their Makefile.
1. $(JSMN_OBJS) is not set anywhere.
2. You don't need to depend on CCAN_HEADERS, COMMON_HEADERS or JSMN_HEADERS: the top level Makefile has all object depedning on it.
3. Similarly, CCAN_OBJS.
4. Every object file should be rebuilt if its Makefile changes.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-10-23 06:44:04 +10:30
Rusty Russell
e120f87083 Makefile: create a library containing common, wire and bitcoin objects.
This means we don't have to manually choose what to link against,
which is much of the complexity of our Makefiles: the compiler will
automatically use any object files it needs to link.

We already do this for ccan as libccan.a, now we have libcommon.a.

We don't link against it for *everything*, as some tests require their own
versions.

Notes:
1. I get rid of the weird plugins/test/Makefile2 (accidental commit?)
2. Many tests change due to update-mocks.
3. In some places I added the missing dependency on the Makefile itself, though most are in the next
   patch.

Before:
	Total program size:     221366528
	Total tests size:       364243856

After:
	Total program size:     190733656
	Total tests size:       337880888

Build time from make clean (RUST=0) (includes building external libs):

Before:
	real    0m38.227000-44.245000(41.8222+/-1.6)s
	user    3m2.105000-33.696000(23.1442+/-8.4)s
	sys     0m35.054000-42.269000(39.7231+/-2)s
After:
	real    0m38.944000-40.416000(40.1131+/-0.4)s
	user    3m6.790000-17.159000(15.0571+/-2.8)s
	sys     0m35.304000-37.336000(36.8942+/-0.57)s

Build time after touch config.vars (RUST=0):

Before:
	real    0m18.928000-22.776000(21.5084+/-1.1)s
	user    2m8.613000-36.567000(27.7281+/-7.7)s
	sys     0m20.458000-23.436000(22.3963+/-0.77)s

After:
	real    0m19.831000-21.862000(21.5528+/-0.58)s
	user    2m15.361000-30.731000(28.4798+/-4.4)s
	sys     0m21.056000-22.339000(22.0346+/-0.35)s

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

rusty@rusty-Framework:~/devel/cvs/lightni
2025-10-23 06:44:04 +10:30
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