Skip to content

Commit c0dd3cd

Browse files
Lagrang3ShahanaFarooqui
authored andcommitted
renepay: disabled channels in a map
Expecting to have more than just a bunch of disabled channels if we prune the lightning network heavily I am changing the internal data structure of disabledmap from a simple array to a hashtable. Have a finer control over disabled channels by targeting short_channel_id_dir instead of short_channel_id, ie. we can disable a single direction of a channel. Signed-off-by: Lagrang3 <[email protected]>
1 parent 7ffd0a3 commit c0dd3cd

File tree

12 files changed

+157
-68
lines changed

12 files changed

+157
-68
lines changed

plugins/renepay/disabledmap.c

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,71 @@ struct disabledmap *disabledmap_new(const tal_t *ctx)
77
if (!obj)
88
return NULL;
99

10-
obj->disabled_scids = tal_arr(obj, struct short_channel_id, 0);
11-
obj->warned_scids = tal_arr(obj, struct short_channel_id, 0);
10+
obj->disabled_map = tal(obj, struct scidd_map);
11+
obj->warned_map = tal(obj, struct scidd_map);
12+
obj->disabled_ctx = tal(obj, tal_t);
13+
obj->warned_ctx = tal(obj, tal_t);
1214
obj->disabled_nodes = tal_arr(obj, struct node_id, 0);
1315

14-
if (!obj->disabled_scids || !obj->warned_scids || !obj->disabled_nodes)
16+
if (!obj->disabled_map || !obj->warned_map || !obj->disabled_nodes ||
17+
!obj->disabled_ctx || !obj->warned_ctx)
1518
return tal_free(obj);
19+
20+
scidd_map_init(obj->disabled_map);
21+
scidd_map_init(obj->warned_map);
1622
return obj;
1723
}
1824

1925
// FIXME: check success
2026
void disabledmap_reset(struct disabledmap *p)
2127
{
22-
tal_resize(&p->disabled_scids, 0);
23-
tal_resize(&p->warned_scids, 0);
28+
/* This will remove and free every element in the maps. */
29+
p->warned_ctx = tal_free(p->warned_ctx);
30+
p->disabled_ctx = tal_free(p->disabled_ctx);
31+
2432
tal_resize(&p->disabled_nodes, 0);
33+
34+
p->disabled_ctx = tal(p, tal_t);
35+
p->warned_ctx = tal(p, tal_t);
36+
}
37+
38+
static void remove_scidd(struct short_channel_id_dir *scidd,
39+
struct scidd_map *map)
40+
{
41+
scidd_map_del(map, scidd);
2542
}
2643

2744
// FIXME: check success
2845
void disabledmap_add_channel(struct disabledmap *p,
29-
struct short_channel_id scid)
46+
struct short_channel_id_dir scidd)
3047
{
31-
tal_arr_expand(&p->disabled_scids, scid);
48+
struct short_channel_id_dir *ptr_scidd =
49+
scidd_map_get(p->disabled_map, scidd);
50+
if (ptr_scidd) {
51+
/* htable allows for duplicates, but we don't want duplicates.
52+
*/
53+
return;
54+
}
55+
ptr_scidd =
56+
tal_dup(p->disabled_ctx, struct short_channel_id_dir, &scidd);
57+
scidd_map_add(p->disabled_map, ptr_scidd);
58+
tal_add_destructor2(ptr_scidd, remove_scidd, p->disabled_map);
3259
}
3360

3461
// FIXME: check success
3562
void disabledmap_warn_channel(struct disabledmap *p,
36-
struct short_channel_id scid)
63+
struct short_channel_id_dir scidd)
3764
{
38-
tal_arr_expand(&p->warned_scids, scid);
65+
struct short_channel_id_dir *ptr_scidd =
66+
scidd_map_get(p->warned_map, scidd);
67+
if (ptr_scidd) {
68+
/* htable allows for duplicates, but we don't want duplicates.
69+
*/
70+
return;
71+
}
72+
ptr_scidd = tal_dup(p->warned_ctx, struct short_channel_id_dir, &scidd);
73+
scidd_map_add(p->warned_map, ptr_scidd);
74+
tal_add_destructor2(ptr_scidd, remove_scidd, p->warned_map);
3975
}
4076

4177
// FIXME: check success
@@ -45,29 +81,31 @@ void disabledmap_add_node(struct disabledmap *p, struct node_id node)
4581
}
4682

4783
bool disabledmap_channel_is_warned(struct disabledmap *p,
48-
struct short_channel_id scid)
84+
struct short_channel_id_dir scidd)
4985
{
50-
for (size_t i = 0; i < tal_count(p->warned_scids); i++) {
51-
if (short_channel_id_eq(scid, p->warned_scids[i]))
52-
return true;
53-
}
54-
return false;
86+
return scidd_map_get(p->warned_map, scidd) != NULL;
5587
}
5688

5789
bitmap *tal_disabledmap_get_bitmap(const tal_t *ctx, struct disabledmap *p,
5890
const struct gossmap *gossmap)
5991
{
60-
bitmap *disabled =
61-
tal_arrz(ctx, bitmap, BITMAP_NWORDS(gossmap_max_chan_idx(gossmap)));
92+
bitmap *disabled = tal_arrz(
93+
ctx, bitmap, 2 * BITMAP_NWORDS(gossmap_max_chan_idx(gossmap)));
6294
if (!disabled)
6395
return NULL;
6496

6597
/* Disable every channel in the list of disabled scids. */
66-
for (size_t i = 0; i < tal_count(p->disabled_scids); i++) {
98+
struct scidd_map_iter it;
99+
for(struct short_channel_id_dir *scidd = scidd_map_first(p->disabled_map,&it);
100+
scidd;
101+
scidd = scidd_map_next(p->disabled_map, &it)){
102+
67103
struct gossmap_chan *c =
68-
gossmap_find_chan(gossmap, &p->disabled_scids[i]);
104+
gossmap_find_chan(gossmap, &scidd->scid);
69105
if (c)
70-
bitmap_set_bit(disabled, gossmap_chan_idx(gossmap, c));
106+
bitmap_set_bit(disabled,
107+
gossmap_chan_idx(gossmap, c) * 2 +
108+
scidd->dir);
71109
}
72110

73111
/* Disable all channels that lead to a disabled node. */
@@ -79,7 +117,8 @@ bitmap *tal_disabledmap_get_bitmap(const tal_t *ctx, struct disabledmap *p,
79117
int half;
80118
const struct gossmap_chan *c =
81119
gossmap_nth_chan(gossmap, node, j, &half);
82-
bitmap_set_bit(disabled, gossmap_chan_idx(gossmap, c));
120+
bitmap_set_bit(disabled,
121+
gossmap_chan_idx(gossmap, c) * 2 + half);
83122
}
84123
}
85124
return disabled;

plugins/renepay/disabledmap.h

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,60 @@
44
#include "config.h"
55
#include <bitcoin/short_channel_id.h>
66
#include <ccan/bitmap/bitmap.h>
7+
#include <ccan/htable/htable_type.h>
78
#include <common/gossmap.h>
89
#include <common/node_id.h>
910

11+
static inline size_t hash_scidd(const struct short_channel_id_dir scidd)
12+
{
13+
/* scids cost money to generate, so simple hash works here. Letting same
14+
* scid with two directions collide. */
15+
return (scidd.scid.u64 >> 32) ^ (scidd.scid.u64 >> 16) ^ scidd.scid.u64;
16+
}
17+
18+
static inline struct short_channel_id_dir
19+
self_scidd(const struct short_channel_id_dir *self)
20+
{
21+
return *self;
22+
}
23+
24+
static inline bool
25+
my_short_channel_id_dir_eq(const struct short_channel_id_dir *scidd_a,
26+
const struct short_channel_id_dir scidd_b)
27+
{
28+
return short_channel_id_eq(scidd_a->scid, scidd_b.scid) &&
29+
scidd_a->dir == scidd_b.dir;
30+
}
31+
32+
/* A htable for short_channel_id_dir, the structure itself is the element key.
33+
*/
34+
HTABLE_DEFINE_TYPE(struct short_channel_id_dir, self_scidd, hash_scidd,
35+
my_short_channel_id_dir_eq, scidd_map);
36+
1037
struct disabledmap {
1138
/* Channels we decided to disable for various reasons. */
12-
/* FIXME: disabled_scids should be a set rather than an array, so that
13-
* we don't have to worry about disabling the same channel multiple
14-
* times. */
15-
struct short_channel_id *disabled_scids;
39+
struct scidd_map *disabled_map;
40+
tal_t *disabled_ctx;
1641

1742
/* Channels that we flagged for failures. If warned two times we will
1843
* disable it. */
19-
struct short_channel_id *warned_scids;
44+
struct scidd_map *warned_map;
45+
tal_t *warned_ctx;
2046

2147
/* nodes we disable */
48+
// FIXME: use a map also for nodes
2249
struct node_id *disabled_nodes;
2350
};
2451

2552
void disabledmap_reset(struct disabledmap *p);
2653
struct disabledmap *disabledmap_new(const tal_t *ctx);
2754
void disabledmap_add_channel(struct disabledmap *p,
28-
struct short_channel_id scid);
55+
struct short_channel_id_dir scidd);
2956
void disabledmap_warn_channel(struct disabledmap *p,
30-
struct short_channel_id scid);
57+
struct short_channel_id_dir scidd);
3158
void disabledmap_add_node(struct disabledmap *p, struct node_id node);
3259
bool disabledmap_channel_is_warned(struct disabledmap *p,
33-
struct short_channel_id scid);
60+
struct short_channel_id_dir scidd);
3461
bitmap *tal_disabledmap_get_bitmap(const tal_t *ctx, struct disabledmap *p,
3562
const struct gossmap *gossmap);
3663

plugins/renepay/mcf.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,8 @@ static bool channel_is_available(const struct gossmap_chan *c, int dir,
449449
if (!gossmap_chan_set(c, dir))
450450
return false;
451451

452-
const u32 chan_id = gossmap_chan_idx(gossmap, c);
453-
return !bitmap_test_bit(disabled, chan_id);
452+
const u32 chan_idx = gossmap_chan_idx(gossmap, c);
453+
return !bitmap_test_bit(disabled, chan_idx * 2 + dir);
454454
}
455455

456456
// TODO(eduardo): unit test this
@@ -1563,13 +1563,17 @@ static bool check_disabled(const bitmap *disabled,
15631563
assert(gossmap);
15641564
assert(chan_extra_map);
15651565

1566-
if(tal_bytelen(disabled) != bitmap_sizeof(gossmap_max_chan_idx(gossmap)))
1566+
if (tal_bytelen(disabled) !=
1567+
2 * bitmap_sizeof(gossmap_max_chan_idx(gossmap)))
15671568
return false;
15681569

15691570
for (struct gossmap_chan *chan = gossmap_first_chan(gossmap); chan;
15701571
chan = gossmap_next_chan(gossmap, chan)) {
1571-
const u32 chan_id = gossmap_chan_idx(gossmap, chan);
1572-
if (bitmap_test_bit(disabled, chan_id))
1572+
const u32 chan_idx = gossmap_chan_idx(gossmap, chan);
1573+
/* If both directions are disabled anyways, there is no need to
1574+
* fetch their information in chan_extra. */
1575+
if (bitmap_test_bit(disabled, chan_idx * 2 + 0) &&
1576+
bitmap_test_bit(disabled, chan_idx * 2 + 1))
15731577
continue;
15741578

15751579
struct short_channel_id scid = gossmap_chan_scid(gossmap, chan);

plugins/renepay/mods.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ static void gossmod_cb(struct gossmap_localmods *mods,
408408

409409
/* Is it disabled? */
410410
if (!enabled)
411-
payment_disable_chan(payment, scidd->scid, LOG_DBG,
411+
payment_disable_chan(payment, *scidd, LOG_DBG,
412412
"listpeerchannels says not enabled");
413413

414414
/* Also update the uncertainty network by fixing the liquidity of the

plugins/renepay/payment.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ static struct command_result *payment_finish(struct payment *p)
366366
return my_command_finish(p, cmd);
367367
}
368368

369-
void payment_disable_chan(struct payment *p, struct short_channel_id scid,
369+
void payment_disable_chan(struct payment *p, struct short_channel_id_dir scidd,
370370
enum log_level lvl, const char *fmt, ...)
371371
{
372372
assert(p);
@@ -378,12 +378,12 @@ void payment_disable_chan(struct payment *p, struct short_channel_id scid,
378378
str = tal_vfmt(tmpctx, fmt, ap);
379379
va_end(ap);
380380
payment_note(p, lvl, "disabling %s: %s",
381-
fmt_short_channel_id(tmpctx, scid),
381+
fmt_short_channel_id_dir(tmpctx, &scidd),
382382
str);
383-
disabledmap_add_channel(p->disabledmap, scid);
383+
disabledmap_add_channel(p->disabledmap, scidd);
384384
}
385385

386-
void payment_warn_chan(struct payment *p, struct short_channel_id scid,
386+
void payment_warn_chan(struct payment *p, struct short_channel_id_dir scidd,
387387
enum log_level lvl, const char *fmt, ...)
388388
{
389389
assert(p);
@@ -395,16 +395,16 @@ void payment_warn_chan(struct payment *p, struct short_channel_id scid,
395395
str = tal_vfmt(tmpctx, fmt, ap);
396396
va_end(ap);
397397

398-
if (disabledmap_channel_is_warned(p->disabledmap, scid)) {
399-
payment_disable_chan(p, scid, lvl, "%s, channel warned twice",
398+
if (disabledmap_channel_is_warned(p->disabledmap, scidd)) {
399+
payment_disable_chan(p, scidd, lvl, "%s, channel warned twice",
400400
str);
401401
return;
402402
}
403403

404404
payment_note(
405405
p, lvl, "flagged for warning %s: %s, next time it will be disabled",
406-
fmt_short_channel_id(tmpctx, scid), str);
407-
disabledmap_warn_channel(p->disabledmap, scid);
406+
fmt_short_channel_id_dir(tmpctx, &scidd), str);
407+
disabledmap_warn_channel(p->disabledmap, scidd);
408408
}
409409

410410
void payment_disable_node(struct payment *p, struct node_id node,

plugins/renepay/payment.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,10 @@ struct command_result *payment_fail(struct payment *payment,
167167
/* These log at LOG_DBG, append to notes, and send command notification */
168168
void payment_note(struct payment *p, enum log_level lvl, const char *fmt, ...);
169169

170-
void payment_disable_chan(struct payment *p, struct short_channel_id scid,
170+
void payment_disable_chan(struct payment *p, struct short_channel_id_dir scidd,
171171
enum log_level lvl, const char *fmt, ...);
172172

173-
void payment_warn_chan(struct payment *p, struct short_channel_id scid,
173+
void payment_warn_chan(struct payment *p, struct short_channel_id_dir scidd,
174174
enum log_level lvl, const char *fmt, ...);
175175

176176
void payment_disable_node(struct payment *p, struct node_id node,

plugins/renepay/routebuilder.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ flow_adjust_htlcmax_constraints(struct flow *flow, struct gossmap *gossmap,
4646

4747
if (errorcode == RENEPAY_BAD_CHANNEL) {
4848
// this is a channel that we can disable
49-
// FIXME: log this error?
49+
// FIXME: log this error? disabling both directions?
5050
bitmap_set_bit(disabled_bitmap,
51-
gossmap_chan_idx(gossmap, bad_channel));
51+
gossmap_chan_idx(gossmap, bad_channel) * 2 + 0);
52+
bitmap_set_bit(disabled_bitmap,
53+
gossmap_chan_idx(gossmap, bad_channel) * 2 + 1);
5254
}
5355

5456
// we had an unexpected error
@@ -83,7 +85,8 @@ route_check_constraints(struct route *route, struct gossmap *gossmap,
8385
amount_msat_less(hop->amount,
8486
gossmap_chan_htlc_min(chan, dir))) {
8587
bitmap_set_bit(disabled_bitmap,
86-
gossmap_chan_idx(gossmap, chan));
88+
gossmap_chan_idx(gossmap, chan) * 2 +
89+
dir);
8790
return RENEPAY_BAD_CHANNEL;
8891
}
8992

@@ -164,15 +167,21 @@ struct route **get_routes(const tal_t *ctx,
164167
}
165168

166169
/* Also disable every channel that we don't have in the chan_extra_map.
170+
* We might have channels in the gossmap that are not usable for
171+
* probability computations for example if we don't know their capacity.
172+
* We can tell the solver to ignore those channels by disabling them
173+
* here.
167174
*/
168175
for (struct gossmap_chan *chan = gossmap_first_chan(gossmap); chan;
169176
chan = gossmap_next_chan(gossmap, chan)) {
170177
const u32 chan_id = gossmap_chan_idx(gossmap, chan);
171178
struct short_channel_id scid = gossmap_chan_scid(gossmap, chan);
172179
struct chan_extra *ce =
173180
chan_extra_map_get(uncertainty->chan_extra_map, scid);
174-
if (!ce)
175-
bitmap_set_bit(disabled_bitmap, chan_id);
181+
if (!ce) {
182+
bitmap_set_bit(disabled_bitmap, chan_id * 2 + 0);
183+
bitmap_set_bit(disabled_bitmap, chan_id * 2 + 1);
184+
}
176185
}
177186

178187
const struct gossmap_node *src, *dst;

plugins/renepay/routefail.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,11 @@ static struct command_result *update_gossip_failure(struct command *cmd UNUSED,
129129
* always be present here, but at least the documentation for
130130
* waitsendpay says it is present in the case of error. */
131131
assert(r->route->result->erring_channel);
132-
132+
struct short_channel_id_dir scidd = {
133+
.scid = *r->route->result->erring_channel,
134+
.dir = *r->route->result->erring_direction};
133135
payment_disable_chan(
134-
r->payment, *r->route->result->erring_channel, LOG_INFORM,
136+
r->payment, scidd, LOG_INFORM,
135137
"addgossip failed (%.*s)", json_tok_full_len(result),
136138
json_tok_full(buf, result));
137139
return update_gossip_done(cmd, buf, result, r);
@@ -346,8 +348,11 @@ static struct command_result *handle_failure(struct routefail *r)
346348

347349
} else {
348350
assert(result->erring_channel);
351+
struct short_channel_id_dir scidd = {
352+
.scid = *result->erring_channel,
353+
.dir = *result->erring_direction};
349354
payment_disable_chan(
350-
payment, *result->erring_channel, LOG_INFORM,
355+
payment, scidd, LOG_INFORM,
351356
"%s", onion_wire_name(result->failcode));
352357
}
353358
break;
@@ -398,8 +403,11 @@ static struct command_result *handle_failure(struct routefail *r)
398403
* information and try again. To avoid hitting this
399404
* error again with the same channel we flag it. */
400405
assert(result->erring_channel);
406+
struct short_channel_id_dir scidd = {
407+
.scid = *result->erring_channel,
408+
.dir = *result->erring_direction};
401409
payment_warn_chan(payment,
402-
*result->erring_channel, LOG_INFORM,
410+
scidd, LOG_INFORM,
403411
"received error %s",
404412
onion_wire_name(result->failcode));
405413
}

0 commit comments

Comments
 (0)