Skip to content

Commit 512e491

Browse files
committed
askrene: add layer auto.ignorelocalhtlclimits
The new layer "auto.ignorelocalhtlclimits" helps remove the HTLC_min/max limits on local channels. Changelog-Added: askrene: add layer auto.ignorelocalhtlclimits Signed-off-by: Lagrang3 <[email protected]>
1 parent 6368aa9 commit 512e491

File tree

4 files changed

+80
-3
lines changed

4 files changed

+80
-3
lines changed

contrib/msggen/msggen/schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16117,7 +16117,7 @@
1611716117
"",
1611816118
"Layers are generally maintained by plugins, either to contain persistent information about capacities which have been discovered, or to contain transient information for this particular payment (such as blinded paths or routehints).",
1611916119
"",
16120-
"There are three automatic layers: *auto.localchans* contains information on local channels from this node (including non-public ones), and their exact current spendable capacities. *auto.sourcefree* overrides all channels (including those from previous layers) leading out of the *source* to be zero fee and zero delay. These are both useful in the case where the source is the current node. And *auto.no_mpp_support* forces getroutes to return a single flow, though only basic checks are done that the result is useful."
16120+
"There are four automatic layers: *auto.localchans* contains information on local channels from this node (including non-public ones), and their exact current spendable capacities. *auto.sourcefree* overrides all channels (including those from previous layers) leading out of the *source* to be zero fee and zero delay. These are both useful in the case where the source is the current node. *auto.no_mpp_support* forces getroutes to return a single flow, though only basic checks are done that the result is useful. And *auto.ignorelocalhtlclimits* that overrides the HTLC maximum and minimum limits on local channels."
1612116121
],
1612216122
"categories": [
1612316123
"readonly"

doc/schemas/lightning-getroutes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"",
1212
"Layers are generally maintained by plugins, either to contain persistent information about capacities which have been discovered, or to contain transient information for this particular payment (such as blinded paths or routehints).",
1313
"",
14-
"There are three automatic layers: *auto.localchans* contains information on local channels from this node (including non-public ones), and their exact current spendable capacities. *auto.sourcefree* overrides all channels (including those from previous layers) leading out of the *source* to be zero fee and zero delay. These are both useful in the case where the source is the current node. And *auto.no_mpp_support* forces getroutes to return a single flow, though only basic checks are done that the result is useful."
14+
"There are four automatic layers: *auto.localchans* contains information on local channels from this node (including non-public ones), and their exact current spendable capacities. *auto.sourcefree* overrides all channels (including those from previous layers) leading out of the *source* to be zero fee and zero delay. These are both useful in the case where the source is the current node. *auto.no_mpp_support* forces getroutes to return a single flow, though only basic checks are done that the result is useful. And *auto.ignorelocalhtlclimits* that overrides the HTLC maximum and minimum limits on local channels."
1515
],
1616
"categories": [
1717
"readonly"

plugins/askrene/askrene.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ static struct command_result *param_layer_names(struct command *cmd,
8383
/* Must be a known layer name */
8484
if (streq((*arr)[i], "auto.localchans")
8585
|| streq((*arr)[i], "auto.no_mpp_support")
86-
|| streq((*arr)[i], "auto.sourcefree"))
86+
|| streq((*arr)[i], "auto.sourcefree")
87+
|| streq((*arr)[i], "auto.ignorelocalhtlclimits"))
8788
continue;
8889
if (!find_layer(get_askrene(cmd->plugin), (*arr)[i])) {
8990
return command_fail_badparam(cmd, name, buffer, t,
@@ -210,6 +211,39 @@ static struct layer *source_free_layer(const tal_t *ctx,
210211
return layer;
211212
}
212213

214+
/* If we're the payer, the HTLC min/max limits do not apply. */
215+
static struct layer *
216+
source_ignorelimits_layer(const tal_t *ctx, struct askrene *askrene,
217+
const struct node_id *source,
218+
struct gossmap_localmods *localmods)
219+
{
220+
struct gossmap *gossmap = askrene->gossmap;
221+
const struct gossmap_node *srcnode;
222+
const struct amount_msat htlc_min = AMOUNT_MSAT(0),
223+
htlc_max = AMOUNT_MSAT(UINT64_MAX);
224+
struct layer *layer =
225+
new_temp_layer(ctx, askrene, "auto.ignorelocalhtlclimits");
226+
227+
/* We apply this so we see any created channels */
228+
gossmap_apply_localmods(gossmap, localmods);
229+
230+
/* If we're not in map, we complain later */
231+
srcnode = gossmap_find_node(gossmap, source);
232+
233+
for (size_t i = 0; srcnode && i < srcnode->num_chans; i++) {
234+
struct short_channel_id_dir scidd;
235+
const struct gossmap_chan *c;
236+
237+
c = gossmap_nth_chan(gossmap, srcnode, i, &scidd.dir);
238+
scidd.scid = gossmap_chan_scid(gossmap, c);
239+
layer_add_update_channel(layer, &scidd, NULL, &htlc_min,
240+
&htlc_max, NULL, NULL, NULL);
241+
}
242+
gossmap_remove_localmods(gossmap, localmods);
243+
244+
return layer;
245+
}
246+
213247
/* We're going to abuse MCF, and take the largest flow it gives and ram everything
214248
* through it. This is more effective if there's at least a *chance* that can handle
215249
* the full amount.
@@ -398,6 +432,12 @@ static const char *get_routes(const tal_t *ctx,
398432
} else if (streq(layers[i], "auto.no_mpp_support")) {
399433
plugin_log(rq->plugin, LOG_DBG, "Adding auto.no_mpp_support, sorry");
400434
l = remove_small_channel_layer(layers, askrene, amount, localmods);
435+
} else if (streq(layers[i],
436+
"auto.ignorelocalhtlclimits")) {
437+
plugin_log(rq->plugin, LOG_DBG,
438+
"Adding auto.ignorelocalhtlclimits");
439+
l = source_ignorelimits_layer(
440+
layers, askrene, source, localmods);
401441
} else {
402442
assert(streq(layers[i], "auto.sourcefree"));
403443
plugin_log(rq->plugin, LOG_DBG, "Adding auto.sourcefree");

tests/test_askrene.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,43 @@ def test_getroutes_auto_localchans(node_factory):
794794
{'short_channel_id_dir': '1x2x1/1', 'amount_msat': 101000, 'delay': 99 + 6}]])
795795

796796

797+
def test_getroutes_auto_ignorelocalhtlclimits(node_factory):
798+
"""Test getroutes call with auto.ignorelocalhtlclimits layer"""
799+
l1 = node_factory.get_node()
800+
gsfile, nodemap = generate_gossip_store([GenChannel(0, 1, forward=GenChannel.Half(propfee=10000)),
801+
GenChannel(1, 2, forward=GenChannel.Half(propfee=10000))],
802+
nodemap={0: l1.info['id']})
803+
804+
# We get bad signature warnings, since our gossip is made up!
805+
l2 = node_factory.get_node(allow_warning=True, gossip_store_file=gsfile.name)
806+
807+
# Now l2 believes l1 has an entire network behind it.
808+
scid12, _ = l2.fundchannel(l1, 10**6, announce_channel=True)
809+
# Set l2->l1 channel HTCL_max = 0
810+
l2.rpc.setchannel(l1.info["id"], htlcmax=0)
811+
812+
# Cannot find a route unless we use auto.ignorelocalhtlclimits.
813+
with pytest.raises(RpcError, match="We could not find a usable set of paths"):
814+
l2.rpc.getroutes(source=l2.info['id'],
815+
destination=nodemap[2],
816+
amount_msat=100000,
817+
layers=["auto.localchans"],
818+
maxfee_msat=100000,
819+
final_cltv=99)
820+
821+
# This should work
822+
scid21dir = f"{scid12}/{direction(l2.info['id'], l1.info['id'])}"
823+
check_getroute_paths(l2,
824+
l2.info['id'],
825+
nodemap[2],
826+
100000,
827+
maxfee_msat=100000,
828+
layers=['auto.localchans', 'auto.ignorelocalhtlclimits'],
829+
paths=[[{'short_channel_id_dir': scid21dir, 'amount_msat': 102012, 'delay': 99 + 6 + 6 + 6},
830+
{'short_channel_id_dir': '0x1x0/0', 'amount_msat': 102010, 'delay': 99 + 6 + 6},
831+
{'short_channel_id_dir': '1x2x1/1', 'amount_msat': 101000, 'delay': 99 + 6}]])
832+
833+
797834
def test_fees_dont_exceed_constraints(node_factory):
798835
msat = 100000000
799836
max_msat = int(msat * 0.45)

0 commit comments

Comments
 (0)