@@ -174,6 +174,9 @@ static const double CHANNEL_PIVOTS[]={0,0.5,0.8,0.95};
174
174
static const s64 INFINITE = INT64_MAX ;
175
175
static const s64 MU_MAX = 100 ;
176
176
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
+
177
180
/* Let's try this encoding of arcs:
178
181
* Each channel `c` has two possible directions identified by a bit
179
182
* `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)
324
327
* cap_on_capacity -= * capacity ;
325
328
}
326
329
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
+
327
339
/* FIXME: unit test this */
328
340
/* The probability of forwarding a payment amount given a high and low liquidity
329
341
* bounds.
@@ -567,16 +579,15 @@ static void init_linear_network(const tal_t *ctx,
567
579
int half ;
568
580
const struct gossmap_chan * c = gossmap_nth_chan (gossmap ,
569
581
node , j , & half );
582
+ const u32 chan_id = gossmap_chan_idx (gossmap , c );
570
583
571
- if (!gossmap_chan_set ( c , half ) || ! c -> half [ half ]. enabled )
584
+ if (!channel_is_available ( params -> rq , c , half ))
572
585
continue ;
573
586
574
587
/* If a channel insists on more than our total, remove it */
575
588
if (amount_msat_less (params -> amount , gossmap_chan_htlc_min (c , half )))
576
589
continue ;
577
590
578
- const u32 chan_id = gossmap_chan_idx (gossmap , c );
579
-
580
591
const struct gossmap_node * next = gossmap_nth_node (gossmap ,
581
592
c ,!half );
582
593
@@ -644,15 +655,16 @@ struct chan_flow
644
655
* */
645
656
static struct node find_path_or_cycle (
646
657
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 ,
649
660
const struct node source ,
650
661
const s64 * balance ,
651
662
652
663
const struct gossmap_chan * * prev_chan ,
653
664
int * prev_dir ,
654
665
u32 * prev_idx )
655
666
{
667
+ const struct gossmap * gossmap = rq -> gossmap ;
656
668
const size_t max_num_nodes = gossmap_max_node_idx (gossmap );
657
669
bitmap * visited =
658
670
tal_arrz (working_ctx , bitmap , BITMAP_NWORDS (max_num_nodes ));
@@ -670,12 +682,11 @@ static struct node find_path_or_cycle(
670
682
int dir ;
671
683
const struct gossmap_chan * c =
672
684
gossmap_nth_chan (gossmap , cur , i , & dir );
685
+ const u32 c_idx = gossmap_chan_idx (gossmap , c );
673
686
674
- if (!gossmap_chan_set ( c , dir ) || ! c -> half [ dir ]. enabled )
687
+ if (!channel_is_available ( rq , c , dir ))
675
688
continue ;
676
689
677
- const u32 c_idx = gossmap_chan_idx (gossmap , c );
678
-
679
690
/* follow the flow */
680
691
if (chan_flow [c_idx ].half [dir ] > 0 ) {
681
692
const struct gossmap_node * n =
@@ -877,7 +888,7 @@ get_flow_paths(const tal_t *ctx,
877
888
while (balance [source .idx ] < 0 ) {
878
889
prev_chan [source .idx ] = NULL ;
879
890
struct node sink = find_path_or_cycle (
880
- working_ctx , params -> rq -> gossmap , chan_flow , source ,
891
+ working_ctx , params -> rq , chan_flow , source ,
881
892
balance , prev_chan , prev_dir , prev_idx );
882
893
883
894
if (balance [sink .idx ] > 0 )
@@ -1059,22 +1070,6 @@ struct flow **minflow(const tal_t *ctx,
1059
1070
return NULL ;
1060
1071
}
1061
1072
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
-
1078
1073
/* Initialize the data vectors for the single-path solver. */
1079
1074
static void init_linear_network_single_path (
1080
1075
const tal_t * ctx , const struct pay_parameters * params , struct graph * * graph ,
@@ -1105,9 +1100,9 @@ static void init_linear_network_single_path(
1105
1100
const struct gossmap_chan * c =
1106
1101
gossmap_nth_chan (gossmap , node , j , & half );
1107
1102
struct amount_msat mincap , maxcap ;
1103
+ const u32 chan_id = gossmap_chan_idx (gossmap , c );
1108
1104
1109
- if (!gossmap_chan_set (c , half ) ||
1110
- !c -> half [half ].enabled )
1105
+ if (!channel_is_available (params -> rq , c , half ))
1111
1106
continue ;
1112
1107
1113
1108
/* If a channel cannot forward the total amount we don't
@@ -1132,8 +1127,6 @@ static void init_linear_network_single_path(
1132
1127
if (amount_msat_greater_eq (params -> amount , maxcap ))
1133
1128
continue ;
1134
1129
1135
- const u32 chan_id = gossmap_chan_idx (gossmap , c );
1136
-
1137
1130
const struct gossmap_node * next =
1138
1131
gossmap_nth_node (gossmap , c , !half );
1139
1132
@@ -1256,6 +1249,67 @@ struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq,
1256
1249
return NULL ;
1257
1250
}
1258
1251
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
+
1259
1313
/* FIXME: add extra constraint maximum route length, use an activation
1260
1314
* probability cost for each channel. Recall that every activation cost, eg.
1261
1315
* 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,
1287
1341
double delay_feefactor = 1e-6 ;
1288
1342
1289
1343
struct flow * * new_flows = NULL ;
1344
+ struct amount_msat all_deliver ;
1290
1345
1291
1346
* flows = tal_arr (working_ctx , struct flow * , 0 );
1292
1347
1293
1348
/* Re-use the reservation system to make flows aware of each other. */
1294
1349
struct reserve_hop * reservations = new_reservations (working_ctx , rq );
1295
1350
1351
+ /* compute the probability one flow at a time. */
1352
+ * probability = 1.0 ;
1353
+
1296
1354
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 {
1298
1369
1299
- new_flows = solver (working_ctx , rq , srcnode , dstnode ,
1370
+ new_flows =
1371
+ solver (working_ctx , rq , srcnode , dstnode ,
1300
1372
amount_to_deliver , mu , delay_feefactor );
1373
+ }
1374
+
1301
1375
if (!new_flows ) {
1302
1376
error_message = explain_failure (
1303
1377
ctx , rq , srcnode , dstnode , amount_to_deliver );
1304
1378
goto fail ;
1305
1379
}
1306
1380
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 ;
1323
1385
1324
1386
/* 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 );
1327
1388
if (amount_msat_is_zero (all_deliver )) {
1328
1389
/* We removed all flows and we have not modified the
1329
1390
* MCF parameters. We will not have an infinite loop
@@ -1336,6 +1397,15 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
1336
1397
* right now if all_deliver > amount_to_deliver means a bug. */
1337
1398
assert (amount_msat_greater_eq (amount_to_deliver , all_deliver ));
1338
1399
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
+
1339
1409
/* Is this set of flows too expensive?
1340
1410
* We can check if the new flows are within the fee budget,
1341
1411
* 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,
1356
1426
error_message =
1357
1427
rq_log (ctx , rq , LOG_BROKEN ,
1358
1428
"%s: failed to scale the fee budget (%s) by "
1359
- "fraction (%ld )" ,
1429
+ "fraction (%lf )" ,
1360
1430
__func__ , fmt_amount_msat (tmpctx , feebudget ),
1361
1431
deliver_fraction );
1362
1432
goto fail ;
@@ -1422,7 +1492,8 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
1422
1492
/* add the new flows to the final solution */
1423
1493
for (size_t i = 0 ; i < tal_count (new_flows ); i ++ ) {
1424
1494
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 );
1426
1497
create_flow_reservations (rq , & reservations ,
1427
1498
new_flows [i ]);
1428
1499
}
0 commit comments