Skip to content

Commit a471749

Browse files
committed
[WIP] save my changes, organize later
Signed-off-by: Lagrang3 <[email protected]>
1 parent c253cf7 commit a471749

File tree

6 files changed

+396
-491
lines changed

6 files changed

+396
-491
lines changed

plugins/askrene/askrene.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,13 @@ static struct command_result *do_getroutes(struct command *cmd,
559559
/* we temporarily apply localmods */
560560
gossmap_apply_localmods(askrene->gossmap, localmods);
561561

562+
/* I want to be able to disable channels while working on this query.
563+
* Layers are for user interaction and cannot be used for this purpose.
564+
*/
565+
rq->disabled_chans =
566+
tal_arrz(rq, bitmap,
567+
2 * BITMAP_NWORDS(gossmap_max_chan_idx(askrene->gossmap)));
568+
562569
/* localmods can add channels, so we need to allocate biases array
563570
* *afterwards* */
564571
rq->biases =

plugins/askrene/askrene.h

Lines changed: 4 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>
@@ -60,6 +61,9 @@ struct route_query {
6061

6162
/* Additional per-htlc cost for local channels */
6263
const struct additional_cost_htable *additional_costs;
64+
65+
/* channels we disable during computation to meet constraints */
66+
bitmap *disabled_chans;
6367
};
6468

6569
/* Given a gossmap channel, get the current known min/max */

plugins/askrene/flow.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,25 @@ struct amount_msat flowset_delivers(struct plugin *plugin,
3232
return final;
3333
}
3434

35-
static double edge_probability(struct amount_msat sent,
36-
struct amount_msat mincap,
37-
struct amount_msat maxcap,
38-
struct amount_msat used)
35+
/* Stolen whole-cloth from @Lagrang3 in renepay's flow.c. Wrong
36+
* because of lc overhead in reservations! */
37+
static double edge_probability(const struct route_query *rq,
38+
const struct short_channel_id_dir *scidd,
39+
struct amount_msat sent)
3940
{
4041
struct amount_msat numerator, denominator;
42+
struct amount_msat mincap, maxcap, additional;
43+
const struct gossmap_chan *c = gossmap_find_chan(rq->gossmap, &scidd->scid);
4144

42-
if (!amount_msat_sub(&mincap, mincap, used))
43-
mincap = AMOUNT_MSAT(0);
44-
if (!amount_msat_sub(&maxcap, maxcap, used))
45-
maxcap = AMOUNT_MSAT(0);
45+
get_constraints(rq, c, scidd->dir, &mincap, &maxcap);
46+
47+
/* We add an extra per-htlc reservation for the *next* HTLC, so we "over-reserve"
48+
* on local channels. Undo that! */
49+
additional = get_additional_per_htlc_cost(rq, scidd);
50+
if (!amount_msat_accumulate(&sent, additional))
51+
plugin_err(rq->plugin,
52+
"%s: Adding additional per HTLC cost to send amount",
53+
__func__);
4654

4755
if (amount_msat_less_eq(sent, mincap))
4856
return 1.0;
@@ -129,10 +137,11 @@ double flow_probability(const struct flow *flow,
129137

130138
for (int i = (int)pathlen - 1; i >= 0; i--) {
131139
const struct half_chan *h = flow_edge(flow, i);
132-
struct amount_msat mincap, maxcap;
140+
struct short_channel_id_dir scidd;
141+
scidd.scid = gossmap_chan_scid(rq->gossmap, flow->path[i]);
142+
scidd.dir = flow->dirs[i];
133143

134-
get_constraints(rq, flow->path[i], flow->dirs[i], &mincap, &maxcap);
135-
prob *= edge_probability(spend, mincap, maxcap, AMOUNT_MSAT(0));
144+
prob *= edge_probability(rq, &scidd, spend);
136145

137146
if (!amount_msat_add_fee(&spend, h->base_fee,
138147
h->proportional_fee)) {

plugins/askrene/mcf.c

Lines changed: 122 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ static const double CHANNEL_PIVOTS[]={0,0.5,0.8,0.95};
174174
static const s64 INFINITE = INT64_MAX;
175175
static const s64 MU_MAX = 100;
176176

177+
/* every payment under 1000sat will be routed through a single path */
178+
static const struct amount_msat SINGLE_PATH_THRESHOLD = AMOUNT_MSAT(1000000);
179+
177180
/* Let's try this encoding of arcs:
178181
* Each channel `c` has two possible directions identified by a bit
179182
* `half` or `!half`, and each one of them has to be
@@ -324,6 +327,15 @@ static void set_capacity(s64 *capacity, u64 value, u64 *cap_on_capacity)
324327
*cap_on_capacity -= *capacity;
325328
}
326329

330+
/* Helper to check whether a channel is available */
331+
static bool channel_is_available(const struct route_query *rq,
332+
const struct gossmap_chan *chan, const int dir)
333+
{
334+
const u32 c_idx = gossmap_chan_idx(rq->gossmap, chan);
335+
return gossmap_chan_set(chan, dir) && chan->half[dir].enabled &&
336+
!bitmap_test_bit(rq->disabled_chans, c_idx * 2 + dir);
337+
}
338+
327339
/* FIXME: unit test this */
328340
/* The probability of forwarding a payment amount given a high and low liquidity
329341
* bounds.
@@ -567,16 +579,15 @@ static void init_linear_network(const tal_t *ctx,
567579
int half;
568580
const struct gossmap_chan *c = gossmap_nth_chan(gossmap,
569581
node, j, &half);
582+
const u32 chan_id = gossmap_chan_idx(gossmap, c);
570583

571-
if (!gossmap_chan_set(c, half) || !c->half[half].enabled)
584+
if (!channel_is_available(params->rq, c, half))
572585
continue;
573586

574587
/* If a channel insists on more than our total, remove it */
575588
if (amount_msat_less(params->amount, gossmap_chan_htlc_min(c, half)))
576589
continue;
577590

578-
const u32 chan_id = gossmap_chan_idx(gossmap, c);
579-
580591
const struct gossmap_node *next = gossmap_nth_node(gossmap,
581592
c,!half);
582593

@@ -644,15 +655,16 @@ struct chan_flow
644655
* */
645656
static struct node find_path_or_cycle(
646657
const tal_t *working_ctx,
647-
const struct gossmap *gossmap,
648-
const struct chan_flow *chan_flow,
658+
const struct route_query *rq,
659+
const struct chan_flow *chan_flow,
649660
const struct node source,
650661
const s64 *balance,
651662

652663
const struct gossmap_chan **prev_chan,
653664
int *prev_dir,
654665
u32 *prev_idx)
655666
{
667+
const struct gossmap *gossmap = rq->gossmap;
656668
const size_t max_num_nodes = gossmap_max_node_idx(gossmap);
657669
bitmap *visited =
658670
tal_arrz(working_ctx, bitmap, BITMAP_NWORDS(max_num_nodes));
@@ -670,12 +682,11 @@ static struct node find_path_or_cycle(
670682
int dir;
671683
const struct gossmap_chan *c =
672684
gossmap_nth_chan(gossmap, cur, i, &dir);
685+
const u32 c_idx = gossmap_chan_idx(gossmap, c);
673686

674-
if (!gossmap_chan_set(c, dir) || !c->half[dir].enabled)
687+
if (!channel_is_available(rq, c, dir))
675688
continue;
676689

677-
const u32 c_idx = gossmap_chan_idx(gossmap, c);
678-
679690
/* follow the flow */
680691
if (chan_flow[c_idx].half[dir] > 0) {
681692
const struct gossmap_node *n =
@@ -877,7 +888,7 @@ get_flow_paths(const tal_t *ctx,
877888
while (balance[source.idx] < 0) {
878889
prev_chan[source.idx] = NULL;
879890
struct node sink = find_path_or_cycle(
880-
working_ctx, params->rq->gossmap, chan_flow, source,
891+
working_ctx, params->rq, chan_flow, source,
881892
balance, prev_chan, prev_dir, prev_idx);
882893

883894
if (balance[sink.idx] > 0)
@@ -1059,22 +1070,6 @@ struct flow **minflow(const tal_t *ctx,
10591070
return NULL;
10601071
}
10611072

1062-
static struct amount_msat linear_flows_cost(struct flow **flows,
1063-
struct amount_msat total_amount,
1064-
double delay_feefactor)
1065-
{
1066-
struct amount_msat total = AMOUNT_MSAT(0);
1067-
1068-
for (size_t i = 0; i < tal_count(flows); i++) {
1069-
if (!amount_msat_accumulate(&total,
1070-
linear_flow_cost(flows[i],
1071-
total_amount,
1072-
delay_feefactor)))
1073-
abort();
1074-
}
1075-
return total;
1076-
}
1077-
10781073
/* Initialize the data vectors for the single-path solver. */
10791074
static void init_linear_network_single_path(
10801075
const tal_t *ctx, const struct pay_parameters *params, struct graph **graph,
@@ -1105,9 +1100,9 @@ static void init_linear_network_single_path(
11051100
const struct gossmap_chan *c =
11061101
gossmap_nth_chan(gossmap, node, j, &half);
11071102
struct amount_msat mincap, maxcap;
1103+
const u32 chan_id = gossmap_chan_idx(gossmap, c);
11081104

1109-
if (!gossmap_chan_set(c, half) ||
1110-
!c->half[half].enabled)
1105+
if (!channel_is_available(params->rq, c, half))
11111106
continue;
11121107

11131108
/* If a channel cannot forward the total amount we don't
@@ -1132,8 +1127,6 @@ static void init_linear_network_single_path(
11321127
if (amount_msat_greater_eq(params->amount, maxcap))
11331128
continue;
11341129

1135-
const u32 chan_id = gossmap_chan_idx(gossmap, c);
1136-
11371130
const struct gossmap_node *next =
11381131
gossmap_nth_node(gossmap, c, !half);
11391132

@@ -1256,6 +1249,67 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
12561249
return NULL;
12571250
}
12581251

1252+
/* Get the scidd for the i'th hop in flow */
1253+
static void get_scidd(const struct gossmap *gossmap, const struct flow *flow,
1254+
size_t i, struct short_channel_id_dir *scidd)
1255+
{
1256+
scidd->scid = gossmap_chan_scid(gossmap, flow->path[i]);
1257+
scidd->dir = flow->dirs[i];
1258+
}
1259+
1260+
/* We use an fp16_t approximatin for htlc_max/min: this gets the exact value. */
1261+
static struct amount_msat
1262+
get_chan_htlc_max(const struct route_query *rq, const struct gossmap_chan *c,
1263+
const struct short_channel_id_dir *scidd)
1264+
{
1265+
struct amount_msat htlc_max;
1266+
1267+
gossmap_chan_get_update_details(rq->gossmap, c, scidd->dir, NULL, NULL,
1268+
NULL, NULL, NULL, NULL, NULL,
1269+
&htlc_max);
1270+
return htlc_max;
1271+
}
1272+
1273+
static struct amount_msat
1274+
get_chan_htlc_min(const struct route_query *rq, const struct gossmap_chan *c,
1275+
const struct short_channel_id_dir *scidd)
1276+
{
1277+
struct amount_msat htlc_min;
1278+
1279+
gossmap_chan_get_update_details(rq->gossmap, c, scidd->dir, NULL, NULL,
1280+
NULL, NULL, NULL, NULL, &htlc_min,
1281+
NULL);
1282+
return htlc_min;
1283+
}
1284+
1285+
static bool check_htlc_limits(struct route_query *rq, struct flow **flows)
1286+
{
1287+
1288+
for (size_t k = 0; k < tal_count(flows); k++) {
1289+
struct flow *flow = flows[k];
1290+
size_t pathlen = tal_count(flow->path);
1291+
struct amount_msat hop_amt = flow->delivers;
1292+
for (size_t i = pathlen - 1; i < pathlen; i--) {
1293+
const struct half_chan *h = flow_edge(flow, i);
1294+
struct short_channel_id_dir scidd;
1295+
1296+
get_scidd(rq->gossmap, flow, i, &scidd);
1297+
struct amount_msat htlc_min =
1298+
get_chan_htlc_min(rq, flow->path[i], &scidd);
1299+
struct amount_msat htlc_max =
1300+
get_chan_htlc_max(rq, flow->path[i], &scidd);
1301+
if (amount_msat_greater(hop_amt, htlc_max) ||
1302+
amount_msat_less(hop_amt, htlc_min))
1303+
return false;
1304+
1305+
if (!amount_msat_add_fee(&hop_amt, h->base_fee,
1306+
h->proportional_fee))
1307+
abort();
1308+
}
1309+
}
1310+
return true;
1311+
}
1312+
12591313
/* FIXME: add extra constraint maximum route length, use an activation
12601314
* probability cost for each channel. Recall that every activation cost, eg.
12611315
* base fee and activation probability can only be properly added modifying the
@@ -1287,43 +1341,50 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
12871341
double delay_feefactor = 1e-6;
12881342

12891343
struct flow **new_flows = NULL;
1344+
struct amount_msat all_deliver;
12901345

12911346
*flows = tal_arr(working_ctx, struct flow *, 0);
12921347

12931348
/* Re-use the reservation system to make flows aware of each other. */
12941349
struct reserve_hop *reservations = new_reservations(working_ctx, rq);
12951350

1351+
/* compute the probability one flow at a time. */
1352+
*probability = 1.0;
1353+
12961354
while (!amount_msat_is_zero(amount_to_deliver)) {
1297-
new_flows = tal_free(new_flows);
1355+
new_flows = tal_free(new_flows);
1356+
1357+
/* If the amount_to_deliver is very small we better use a single
1358+
* path computation because:
1359+
* 1. we save cpu cycles
1360+
* 2. we have better control over htlc_min violations.
1361+
* We need to make the distinction here because after
1362+
* refine_with_fees_and_limits we might have a set of flows that
1363+
* do not deliver the entire payment amount by just a small
1364+
* amount. */
1365+
if(amount_msat_less_eq(amount_to_deliver, SINGLE_PATH_THRESHOLD)){
1366+
new_flows = single_path_flow(working_ctx, rq, srcnode, dstnode,
1367+
amount_to_deliver, mu, delay_feefactor);
1368+
} else {
12981369

1299-
new_flows = solver(working_ctx, rq, srcnode, dstnode,
1370+
new_flows =
1371+
solver(working_ctx, rq, srcnode, dstnode,
13001372
amount_to_deliver, mu, delay_feefactor);
1373+
}
1374+
13011375
if (!new_flows) {
13021376
error_message = explain_failure(
13031377
ctx, rq, srcnode, dstnode, amount_to_deliver);
13041378
goto fail;
13051379
}
13061380

1307-
// TODO:
1308-
// trim flows to meet htlc_max constraints
1309-
// trim flows to deliver no more amount_to_deliver
1310-
//
1311-
// ? increase flows to deliver no less than amount_to_deliver,
1312-
// but
1313-
// take max_deliverable into consideration
1314-
//
1315-
// remove flows that have htlc_min violations, disable the
1316-
// culprit channel
1317-
1318-
// for each flow
1319-
// compute amounts and adjust to htlc max
1320-
// disable some channels to void violations of htlc_min
1321-
// call refine_with_fees_and_limits?
1322-
//
1381+
error_message = refine_with_fees_and_limits(
1382+
ctx, rq, amount_to_deliver, &new_flows);
1383+
if (error_message)
1384+
goto fail;
13231385

13241386
/* we finished removing flows and excess */
1325-
const struct amount_msat all_deliver =
1326-
flowset_delivers(rq->plugin, new_flows);
1387+
all_deliver = flowset_delivers(rq->plugin, new_flows);
13271388
if (amount_msat_is_zero(all_deliver)) {
13281389
/* We removed all flows and we have not modified the
13291390
* MCF parameters. We will not have an infinite loop
@@ -1336,6 +1397,15 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
13361397
* right now if all_deliver > amount_to_deliver means a bug. */
13371398
assert(amount_msat_greater_eq(amount_to_deliver, all_deliver));
13381399

1400+
/* we should have fixed all htlc violations, "don't trust,
1401+
* verify" */
1402+
assert(check_htlc_limits(rq, new_flows));
1403+
1404+
/* no flows should send 0 amount */
1405+
for (size_t i = 0; i < tal_count(new_flows); i++) {
1406+
assert(!amount_msat_is_zero(new_flows[i]->delivers));
1407+
}
1408+
13391409
/* Is this set of flows too expensive?
13401410
* We can check if the new flows are within the fee budget,
13411411
* however in some cases we have discarded some flows at this
@@ -1356,7 +1426,7 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
13561426
error_message =
13571427
rq_log(ctx, rq, LOG_BROKEN,
13581428
"%s: failed to scale the fee budget (%s) by "
1359-
"fraction (%ld)",
1429+
"fraction (%lf)",
13601430
__func__, fmt_amount_msat(tmpctx, feebudget),
13611431
deliver_fraction);
13621432
goto fail;
@@ -1422,7 +1492,8 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
14221492
/* add the new flows to the final solution */
14231493
for (size_t i = 0; i < tal_count(new_flows); i++) {
14241494
tal_arr_expand(flows, new_flows[i]);
1425-
tal_steal(flows, new_flows[i]);
1495+
tal_steal(*flows, new_flows[i]);
1496+
*probability *= flow_probability(new_flows[i], rq);
14261497
create_flow_reservations(rq, &reservations,
14271498
new_flows[i]);
14281499
}

0 commit comments

Comments
 (0)