@@ -949,6 +949,46 @@ get_flow_paths(const tal_t *ctx,
949
949
return flows ;
950
950
}
951
951
952
+ /* Given a single path build a flow set. */
953
+ static struct flow * *
954
+ get_flow_singlepath (const tal_t * ctx , const tal_t * working_ctx ,
955
+ const struct graph * graph , const struct gossmap * gossmap ,
956
+ const struct node source , const struct node destination ,
957
+ const u64 pay_amount , const struct arc * prev )
958
+ {
959
+ struct flow * * flows = tal_arr (ctx , struct flow * , 0 );
960
+
961
+ size_t length = 0 ;
962
+
963
+ for (u32 cur_idx = destination .idx ; cur_idx != source .idx ;) {
964
+ assert (cur_idx != INVALID_INDEX );
965
+ length ++ ;
966
+ struct arc arc = prev [cur_idx ];
967
+ struct node next = arc_tail (graph , arc );
968
+ cur_idx = next .idx ;
969
+ }
970
+ struct flow * f = tal (ctx , struct flow );
971
+ f -> path = tal_arr (f , const struct gossmap_chan * , length );
972
+ f -> dirs = tal_arr (f , int , length );
973
+
974
+ for (u32 cur_idx = destination .idx ; cur_idx != source .idx ;) {
975
+ int chandir ;
976
+ u32 chanidx ;
977
+ struct arc arc = prev [cur_idx ];
978
+ arc_to_parts (arc , & chanidx , & chandir , NULL , NULL );
979
+
980
+ length -- ;
981
+ f -> path [length ] = gossmap_chan_byidx (gossmap , chanidx );
982
+ f -> dirs [length ] = chandir ;
983
+
984
+ struct node next = arc_tail (graph , arc );
985
+ cur_idx = next .idx ;
986
+ }
987
+
988
+ tal_arr_expand (& flows , f );
989
+ return flows ;
990
+ }
991
+
952
992
// TODO(eduardo): choose some default values for the minflow parameters
953
993
/* eduardo: I think it should be clear that this module deals with linear
954
994
* flows, ie. base fees are not considered. Hence a flow along a path is
@@ -967,8 +1007,7 @@ struct flow **minflow(const tal_t *ctx,
967
1007
const struct gossmap_node * target ,
968
1008
struct amount_msat amount ,
969
1009
u32 mu ,
970
- double delay_feefactor ,
971
- bool single_part )
1010
+ double delay_feefactor )
972
1011
{
973
1012
struct flow * * flow_paths ;
974
1013
/* We allocate everything off this, and free it at the end,
@@ -1051,31 +1090,105 @@ struct flow **minflow(const tal_t *ctx,
1051
1090
goto fail ;
1052
1091
}
1053
1092
tal_free (working_ctx );
1093
+ return flow_paths ;
1054
1094
1055
- /* This is dumb, but if you don't support MPP you don't deserve any
1056
- * better. Pile it into the largest part if not already. */
1057
- if (single_part ) {
1058
- struct flow * best = flow_paths [0 ];
1059
- for (size_t i = 1 ; i < tal_count (flow_paths ); i ++ ) {
1060
- if (amount_msat_greater (flow_paths [i ]-> delivers , best -> delivers ))
1061
- best = flow_paths [i ];
1062
- }
1063
- for (size_t i = 0 ; i < tal_count (flow_paths ); i ++ ) {
1064
- if (flow_paths [i ] == best )
1065
- continue ;
1066
- if (!amount_msat_accumulate (& best -> delivers ,
1067
- flow_paths [i ]-> delivers )) {
1068
- rq_log (tmpctx , rq , LOG_BROKEN ,
1069
- "%s: failed to extract accumulate flow paths %s+%s" ,
1070
- __func__ ,
1071
- fmt_amount_msat (tmpctx , best -> delivers ),
1072
- fmt_amount_msat (tmpctx , flow_paths [i ]-> delivers ));
1073
- goto fail ;
1074
- }
1075
- }
1076
- flow_paths [0 ] = best ;
1077
- tal_resize (& flow_paths , 1 );
1095
+ fail :
1096
+ tal_free (working_ctx );
1097
+ return NULL ;
1098
+ }
1099
+
1100
+ static struct flow * * single_path_flow (const tal_t * ctx ,
1101
+ const struct route_query * rq ,
1102
+ const struct gossmap_node * source ,
1103
+ const struct gossmap_node * target ,
1104
+ struct amount_msat amount , u32 mu ,
1105
+ double delay_feefactor )
1106
+ {
1107
+ struct flow * * flow_paths ;
1108
+ /* We allocate everything off this, and free it at the end,
1109
+ * as we can be called multiple times without cleaning tmpctx! */
1110
+ tal_t * working_ctx = tal (NULL , char );
1111
+ struct pay_parameters * params = tal (working_ctx , struct pay_parameters );
1112
+
1113
+ params -> rq = rq ;
1114
+ params -> source = source ;
1115
+ params -> target = target ;
1116
+ params -> amount = amount ;
1117
+ /* for the single-path solver the accuracy does not detriment
1118
+ * performance */
1119
+ params -> accuracy = AMOUNT_MSAT (1000 );
1120
+ params -> delay_feefactor = delay_feefactor ;
1121
+ params -> base_fee_penalty = base_fee_penalty_estimate (amount );
1122
+
1123
+ // build the uncertainty network with linearization and residual arcs
1124
+ struct linear_network * linear_network =
1125
+ init_linear_network (working_ctx , params );
1126
+
1127
+ const size_t max_num_chans = gossmap_max_chan_idx (rq -> gossmap );
1128
+ const size_t max_num_arcs = max_num_chans * ARCS_PER_CHANNEL ;
1129
+ const size_t max_num_nodes = gossmap_max_node_idx (rq -> gossmap );
1130
+
1131
+ struct graph * graph = graph_new (working_ctx , max_num_nodes ,
1132
+ max_num_arcs , ARC_DUAL_BITOFF );
1133
+ double * arc_prob_cost = tal_arr (working_ctx , double , max_num_arcs );
1134
+ for (size_t i = 0 ; i < max_num_arcs ; ++ i )
1135
+ arc_prob_cost [i ] = DBL_MAX ;
1136
+ s64 * arc_fee_cost = tal_arr (working_ctx , s64 , max_num_arcs );
1137
+ for (size_t i = 0 ; i < max_num_arcs ; ++ i )
1138
+ arc_fee_cost [i ] = INT64_MAX ;
1139
+ s64 * capacity = tal_arrz (working_ctx , s64 , max_num_arcs );
1140
+
1141
+ // FIXME: compute costs for arcs
1142
+
1143
+ const struct node dst = {.idx = gossmap_node_idx (rq -> gossmap , target )};
1144
+ const struct node src = {.idx = gossmap_node_idx (rq -> gossmap , source )};
1145
+
1146
+ /* Since we have constraint accuracy, ask to find a payment solution
1147
+ * that can pay a bit more than the actual value rather than undershoot
1148
+ * it. That's why we use the ceil function here. */
1149
+ const u64 pay_amount =
1150
+ amount_msat_ratio_ceil (params -> amount , params -> accuracy );
1151
+
1152
+ // FIXME: combine cost functions
1153
+ combine_cost_function (working_ctx , linear_network , residual_network ,
1154
+ rq -> biases , mu );
1155
+
1156
+ s64 * potential = tal_arrz (working_ctx , s64 , max_num_nodes );
1157
+ s64 * distance = tal_arrz (working_ctx , s64 , max_num_nodes );
1158
+ struct arc * prev = tal_arrz (working_ctx , struct arc , max_num_nodes );
1159
+
1160
+ /* We solve a linear cost flow problem. */
1161
+ if (!dijkstra_path (working_ctx , linear_network -> graph , src , dst ,
1162
+ /* prune = */ true, residual_network -> cap ,
1163
+ pay_amount , residual_network -> cost , potential , prev ,
1164
+ distance )) {
1165
+ rq_log (tmpctx , rq , LOG_BROKEN ,
1166
+ "%s: could not find a feasible single path" , __func__ );
1167
+ goto fail ;
1078
1168
}
1169
+
1170
+ /* We dissect the flow into payment routes.
1171
+ * Actual amounts considering fees are computed for every
1172
+ * channel in the routes. */
1173
+ flow_paths =
1174
+ get_flow_singlepath (ctx , working_ctx , linear_network -> graph ,
1175
+ rq -> gossmap , src , dst , pay_amount , prev );
1176
+ if (!flow_paths ) {
1177
+ rq_log (tmpctx , rq , LOG_BROKEN ,
1178
+ "%s: failed to extract flow paths from the single-path "
1179
+ "solution" ,
1180
+ __func__ );
1181
+ goto fail ;
1182
+ }
1183
+ if (tal_count (flow_paths ) != 1 ) {
1184
+ rq_log (
1185
+ tmpctx , rq , LOG_BROKEN ,
1186
+ "%s: single-path solution returned a multi route solution" ,
1187
+ __func__ );
1188
+ goto fail ;
1189
+ }
1190
+ tal_free (working_ctx );
1191
+
1079
1192
return flow_paths ;
1080
1193
1081
1194
fail :
@@ -1099,22 +1212,22 @@ static struct amount_msat linear_flows_cost(struct flow **flows,
1099
1212
return total ;
1100
1213
}
1101
1214
1102
-
1103
- const char * default_routes (const tal_t * ctx , struct route_query * rq ,
1104
- const struct gossmap_node * srcnode ,
1105
- const struct gossmap_node * dstnode ,
1106
- struct amount_msat amount , bool single_path ,
1107
- struct amount_msat maxfee , u32 finalcltv ,
1108
- u32 maxdelay , struct flow * * * flows ,
1109
- double * probability )
1215
+ static const char * linear_routes (
1216
+ const tal_t * ctx , struct route_query * rq ,
1217
+ const struct gossmap_node * srcnode , const struct gossmap_node * dstnode ,
1218
+ struct amount_msat amount , struct amount_msat maxfee , u32 finalcltv ,
1219
+ u32 maxdelay , struct flow * * * flows , double * probability ,
1220
+ struct flow * * (* solver_cb )(const tal_t * , const struct route_query * ,
1221
+ const struct gossmap_node * ,
1222
+ const struct gossmap_node * , struct amount_msat ,
1223
+ u32 , double ))
1110
1224
{
1111
1225
const char * ret ;
1112
1226
double delay_feefactor = 1.0 / 1000000 ;
1113
1227
1114
1228
/* First up, don't care about fees (well, just enough to tiebreak!) */
1115
1229
u32 mu = 1 ;
1116
- * flows = minflow (ctx , rq , srcnode , dstnode , amount , mu , delay_feefactor ,
1117
- single_path );
1230
+ * flows = solver_cb (ctx , rq , srcnode , dstnode , amount , mu , delay_feefactor );
1118
1231
if (!* flows ) {
1119
1232
ret = explain_failure (ctx , rq , srcnode , dstnode , amount );
1120
1233
goto fail ;
@@ -1128,8 +1241,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
1128
1241
" (> %i), retrying with delay_feefactor %f..." ,
1129
1242
flows_worst_delay (* flows ), maxdelay - finalcltv ,
1130
1243
delay_feefactor );
1131
- * flows = minflow (ctx , rq , srcnode , dstnode , amount , mu ,
1132
- delay_feefactor , single_path );
1244
+ * flows = solver_cb (ctx , rq , srcnode , dstnode , amount , mu ,
1245
+ delay_feefactor );
1133
1246
if (!* flows || delay_feefactor > 10 ) {
1134
1247
ret = rq_log (
1135
1248
ctx , rq , LOG_UNUSUAL ,
@@ -1152,9 +1265,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
1152
1265
"retrying with mu of %u%%..." ,
1153
1266
fmt_amount_msat (tmpctx , flowset_fee (rq -> plugin , * flows )),
1154
1267
fmt_amount_msat (tmpctx , maxfee ), mu );
1155
- new_flows =
1156
- minflow (ctx , rq , srcnode , dstnode , amount ,
1157
- mu > 100 ? 100 : mu , delay_feefactor , single_path );
1268
+ new_flows = solver_cb (ctx , rq , srcnode , dstnode , amount ,
1269
+ mu > 100 ? 100 : mu , delay_feefactor );
1158
1270
if (!* flows || mu >= 100 ) {
1159
1271
ret = rq_log (
1160
1272
ctx , rq , LOG_UNUSUAL ,
@@ -1235,3 +1347,27 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
1235
1347
assert (ret != NULL );
1236
1348
return ret ;
1237
1349
}
1350
+
1351
+ const char * default_routes (const tal_t * ctx , struct route_query * rq ,
1352
+ const struct gossmap_node * srcnode ,
1353
+ const struct gossmap_node * dstnode ,
1354
+ struct amount_msat amount , struct amount_msat maxfee ,
1355
+ u32 finalcltv , u32 maxdelay , struct flow * * * flows ,
1356
+ double * probability )
1357
+ {
1358
+ return linear_routes (ctx , rq , srcnode , dstnode , amount , maxfee ,
1359
+ finalcltv , maxdelay , flows , probability , minflow );
1360
+ }
1361
+
1362
+ const char * single_path_routes (const tal_t * ctx , struct route_query * rq ,
1363
+ const struct gossmap_node * srcnode ,
1364
+ const struct gossmap_node * dstnode ,
1365
+ struct amount_msat amount ,
1366
+ struct amount_msat maxfee , u32 finalcltv ,
1367
+ u32 maxdelay , struct flow * * * flows ,
1368
+ double * probability )
1369
+ {
1370
+ return linear_routes (ctx , rq , srcnode , dstnode , amount , maxfee ,
1371
+ finalcltv , maxdelay , flows , probability ,
1372
+ single_path_flow );
1373
+ }
0 commit comments