@@ -949,6 +949,46 @@ get_flow_paths(const tal_t *ctx,
949949 return flows ;
950950}
951951
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+
952992// TODO(eduardo): choose some default values for the minflow parameters
953993/* eduardo: I think it should be clear that this module deals with linear
954994 * 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,
9671007 const struct gossmap_node * target ,
9681008 struct amount_msat amount ,
9691009 u32 mu ,
970- double delay_feefactor ,
971- bool single_part )
1010+ double delay_feefactor )
9721011{
9731012 struct flow * * flow_paths ;
9741013 /* We allocate everything off this, and free it at the end,
@@ -1051,31 +1090,105 @@ struct flow **minflow(const tal_t *ctx,
10511090 goto fail ;
10521091 }
10531092 tal_free (working_ctx );
1093+ return flow_paths ;
10541094
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 ;
10781168 }
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+
10791192 return flow_paths ;
10801193
10811194fail :
@@ -1099,22 +1212,22 @@ static struct amount_msat linear_flows_cost(struct flow **flows,
10991212 return total ;
11001213}
11011214
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 ))
11101224{
11111225 const char * ret ;
11121226 double delay_feefactor = 1.0 / 1000000 ;
11131227
11141228 /* First up, don't care about fees (well, just enough to tiebreak!) */
11151229 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 );
11181231 if (!* flows ) {
11191232 ret = explain_failure (ctx , rq , srcnode , dstnode , amount );
11201233 goto fail ;
@@ -1128,8 +1241,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
11281241 " (> %i), retrying with delay_feefactor %f..." ,
11291242 flows_worst_delay (* flows ), maxdelay - finalcltv ,
11301243 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 );
11331246 if (!* flows || delay_feefactor > 10 ) {
11341247 ret = rq_log (
11351248 ctx , rq , LOG_UNUSUAL ,
@@ -1152,9 +1265,8 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
11521265 "retrying with mu of %u%%..." ,
11531266 fmt_amount_msat (tmpctx , flowset_fee (rq -> plugin , * flows )),
11541267 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 );
11581270 if (!* flows || mu >= 100 ) {
11591271 ret = rq_log (
11601272 ctx , rq , LOG_UNUSUAL ,
@@ -1235,3 +1347,27 @@ const char *default_routes(const tal_t *ctx, struct route_query *rq,
12351347 assert (ret != NULL );
12361348 return ret ;
12371349}
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