Skip to content

Commit 02005e7

Browse files
committed
askrene: refactor disabled channels/nodes
Use a bitmap to mark disabled channels instead of tweaking values in localmods. Signed-off-by: Lagrang3 <[email protected]>
1 parent 6e51873 commit 02005e7

File tree

6 files changed

+83
-32
lines changed

6 files changed

+83
-32
lines changed

plugins/askrene/askrene.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ static const char *get_routes(const tal_t *ctx,
337337

338338
gossmap_apply_localmods(askrene->gossmap, localmods);
339339

340+
rq->disabled = tal_get_disabled_bitmap(rq, rq);
341+
if (!rq->disabled) {
342+
ret = tal_fmt(ctx, "Failed creation of disabled bitmap.");
343+
goto out;
344+
}
345+
340346
srcnode = gossmap_find_node(askrene->gossmap, source);
341347
if (!srcnode) {
342348
ret = tal_fmt(ctx, "Unknown source node %s", fmt_node_id(tmpctx, source));

plugins/askrene/askrene.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define LIGHTNING_PLUGINS_ASKRENE_ASKRENE_H
33
#include "config.h"
44
#include <bitcoin/short_channel_id.h>
5+
#include <ccan/bitmap/bitmap.h>
56
#include <ccan/htable/htable_type.h>
67
#include <ccan/list/list.h>
78
#include <common/amount.h>
@@ -41,6 +42,10 @@ struct route_query {
4142
/* This is *not* updated during a query! Has all layers applied. */
4243
const struct gossmap *gossmap;
4344

45+
/* Bit is set for [idx*2+dir] if that channel is disabled or if it
46+
* belongs to a disabled node.. */
47+
bitmap *disabled;
48+
4449
/* We need to take in-flight payments into account */
4550
const struct reserve_htable *reserved;
4651

plugins/askrene/layer.c

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -323,37 +323,6 @@ void layer_add_localmods(const struct layer *layer,
323323
const struct local_channel *lc;
324324
struct local_channel_hash_iter lcit;
325325

326-
/* First, disable all channels into blocked nodes (local updates
327-
* can add new ones)! */
328-
for (size_t i = 0; i < tal_count(layer->disabled); i++) {
329-
struct route_exclusion ex = layer->disabled[i];
330-
331-
/* Disable all channels of excluded nodes. */
332-
if (ex.type == EXCLUDE_NODE) {
333-
const struct gossmap_node *node;
334-
335-
node = gossmap_find_node(gossmap, &ex.u.node_id);
336-
if (!node)
337-
continue;
338-
for (size_t n = 0; n < node->num_chans; n++) {
339-
struct short_channel_id scid;
340-
struct gossmap_chan *c;
341-
int dir;
342-
c = gossmap_nth_chan(gossmap, node, n, &dir);
343-
scid = gossmap_chan_scid(gossmap, c);
344-
345-
/* Disabled zero-capacity on incoming */
346-
gossmap_local_updatechan(
347-
localmods, scid, AMOUNT_MSAT(0),
348-
AMOUNT_MSAT(0), 0, 0, 0, false, !dir);
349-
}
350-
} else {
351-
gossmap_local_updatechan(
352-
localmods, ex.u.chan_id.scid, AMOUNT_MSAT(0),
353-
AMOUNT_MSAT(0), 0, 0, 0, false, ex.u.chan_id.dir);
354-
}
355-
}
356-
357326
for (lc = local_channel_hash_first(layer->local_channels, &lcit);
358327
lc;
359328
lc = local_channel_hash_next(layer->local_channels, &lcit)) {
@@ -489,3 +458,56 @@ void layer_memleak_mark(struct askrene *askrene, struct htable *memtable)
489458
memleak_scan_htable(memtable, &l->local_channels->raw);
490459
}
491460
}
461+
462+
static void set_channel_bit(bitmap *bm, const struct gossmap *gossmap,
463+
const struct short_channel_id_dir *scidd)
464+
{
465+
const struct gossmap_chan *chan =
466+
gossmap_find_chan(gossmap, &scidd->scid);
467+
468+
if (!chan)
469+
return;
470+
471+
bitmap_set_bit(bm, gossmap_chan_idx(gossmap, chan) * 2 + scidd->dir);
472+
}
473+
474+
static void set_node_channels_bit(bitmap *bm, const struct gossmap *gossmap,
475+
const struct node_id *node_id)
476+
{
477+
const struct gossmap_node *node = gossmap_find_node(gossmap, node_id);
478+
for (size_t k = 0; k < node->num_chans; k++) {
479+
int half;
480+
const struct gossmap_chan *chan =
481+
gossmap_nth_chan(gossmap, node, k, &half);
482+
483+
bitmap_set_bit(bm, gossmap_chan_idx(gossmap, chan) * 2 + half);
484+
bitmap_set_bit(bm, gossmap_chan_idx(gossmap, chan) * 2 + !half);
485+
}
486+
}
487+
488+
bitmap *tal_get_disabled_bitmap(const tal_t *ctx, struct route_query *rq)
489+
{
490+
491+
bitmap *disabled = tal_arrz(
492+
ctx, bitmap, 2 * BITMAP_NWORDS(gossmap_max_chan_idx(rq->gossmap)));
493+
494+
if (!disabled)
495+
return NULL;
496+
497+
/* Disable every channel in the list of disabled scids. */
498+
for (size_t i = 0; i < tal_count(rq->layers); i++) {
499+
const struct layer *l = rq->layers[i];
500+
501+
for (size_t j = 0; j < tal_count(l->disabled); j++) {
502+
const struct route_exclusion *ex = &l->disabled[j];
503+
504+
if (ex->type == EXCLUDE_CHANNEL)
505+
set_channel_bit(disabled, rq->gossmap,
506+
&ex->u.chan_id);
507+
else
508+
set_node_channels_bit(disabled, rq->gossmap,
509+
&ex->u.node_id);
510+
}
511+
}
512+
return disabled;
513+
}

plugins/askrene/layer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,9 @@ void json_add_constraint(struct json_stream *js,
120120

121121
/* Scan for memleaks */
122122
void layer_memleak_mark(struct askrene *askrene, struct htable *memtable);
123+
124+
/* Creates a bitmap of disabled channels. It loops over all layers in the
125+
* query searching for disabled channels and disabled nodes. All channels
126+
* linked to a disabled node will be disabled. */
127+
bitmap *tal_get_disabled_bitmap(const tal_t *ctx, struct route_query *rq);
123128
#endif /* LIGHTNING_PLUGINS_ASKRENE_LAYER_H */

plugins/askrene/mcf.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,11 +583,22 @@ static s64 linear_fee_cost(
583583
return pfee + bfee* base_fee_penalty+ delay*delay_feefactor;
584584
}
585585

586+
static bool channel_is_available(const struct gossmap_chan *c, int dir,
587+
const struct gossmap *gossmap,
588+
const bitmap *disabled)
589+
{
590+
if (!gossmap_chan_set(c, dir))
591+
return false;
592+
const u32 chan_idx = gossmap_chan_idx(gossmap, c);
593+
return !bitmap_test_bit(disabled, chan_idx * 2 + dir);
594+
}
595+
586596
static struct linear_network *
587597
init_linear_network(const tal_t *ctx, const struct pay_parameters *params)
588598
{
589599
struct linear_network * linear_network = tal(ctx, struct linear_network);
590600
const struct gossmap *gossmap = params->rq->gossmap;
601+
const bitmap *disabled = params->rq->disabled;
591602

592603
const size_t max_num_chans = gossmap_max_chan_idx(gossmap);
593604
const size_t max_num_arcs = max_num_chans * ARCS_PER_CHANNEL;
@@ -630,7 +641,7 @@ init_linear_network(const tal_t *ctx, const struct pay_parameters *params)
630641
const struct gossmap_chan *c = gossmap_nth_chan(gossmap,
631642
node, j, &half);
632643

633-
if (!gossmap_chan_set(c, half))
644+
if (!channel_is_available(c, half, gossmap, disabled))
634645
continue;
635646

636647
const u32 chan_id = gossmap_chan_idx(gossmap, c);

tests/test_askrene.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ def test_getroutes(node_factory):
172172
l1.rpc.askrene_disable_channel("chans_disabled", "0x1x0")
173173
l1.rpc.askrene_disable_channel("chans_disabled", "0x2x1")
174174
l1.rpc.askrene_disable_channel("chans_disabled", "0x2x3")
175+
# we can also disable by mistake channels that do not exists
176+
l1.rpc.askrene_disable_channel("chans_disabled", "111x222x333")
175177
with pytest.raises(RpcError, match="Could not find route"):
176178
l1.rpc.getroutes(source=nodemap[0],
177179
destination=nodemap[1],

0 commit comments

Comments
 (0)