22#include <assert.h>
33#include <ccan/asort/asort.h>
44#include <ccan/bitmap/bitmap.h>
5+ #include <ccan/err/err.h>
56#include <ccan/list/list.h>
67#include <ccan/tal/str/str.h>
78#include <ccan/tal/tal.h>
159160 *
160161 * */
161162
163+ #define PANIC (message ) \
164+ errx(1, "Panic in function %s line %d: %s", __func__, __LINE__, \
165+ message);
166+
162167#define PARTS_BITS 2
163168#define CHANNEL_PARTS (1 << PARTS_BITS)
164169
@@ -297,6 +302,10 @@ struct pay_parameters {
297302
298303 double delay_feefactor ;
299304 double base_fee_penalty ;
305+
306+ /* keep this here to have a consistent conversion factor all over.
307+ * Probability Cost (x) = prob_cost_factor * (-log Probability(x)) */
308+ double prob_cost_factor ;
300309};
301310
302311/* Helper function.
@@ -319,6 +328,46 @@ static void set_capacity(s64 *capacity, u64 value, u64 *cap_on_capacity)
319328 * cap_on_capacity -= * capacity ;
320329}
321330
331+ /* FIXME: unit test this */
332+ /* The probability of forwarding a payment amount given a high and low liquidity
333+ * bounds.
334+ * @low: the liquidity is known to be greater or equal than "low"
335+ * @high: the liquidity is known to be less than "high"
336+ * @amount: how much is required to forward */
337+ static double pickhardt_richter_probability (struct amount_msat low ,
338+ struct amount_msat high ,
339+ struct amount_msat amount )
340+ {
341+ struct amount_msat all_states , good_states ;
342+ if (amount_msat_greater_eq (amount , high ))
343+ return 0.0 ;
344+ if (!amount_msat_sub (& amount , amount , low ))
345+ return 1.0 ;
346+ if (!amount_msat_sub (& all_states , high , low ))
347+ PANIC ("we expect high > low" );
348+ if (!amount_msat_sub (& good_states , all_states , amount ))
349+ PANIC ("we expect high > amount" );
350+ return amount_msat_ratio (good_states , all_states );
351+ }
352+
353+ /* Returns the probability of success that this channel is able to forward x
354+ * considering only the bounds on the liquidity. */
355+ static double channel_probability (const struct pay_parameters * params ,
356+ const struct gossmap_chan * c , const int dir ,
357+ struct amount_msat forward )
358+ {
359+ struct amount_msat mincap , maxcap ;
360+ /* This takes into account any payments in progress. */
361+ get_constraints (params -> rq , c , dir , & mincap , & maxcap );
362+ /* Assume if min > max, min is wrong */
363+ if (amount_msat_greater (mincap , maxcap ))
364+ mincap = maxcap ;
365+ /* It is preferable to work on 1msat past the known bound. */
366+ if (!amount_msat_accumulate (& maxcap , amount_msat (1 )))
367+ PANIC ("maxcap + 1msat overflows" );
368+ return pickhardt_richter_probability (mincap , maxcap , forward );
369+ }
370+
322371// TODO(eduardo): unit test this
323372/* Split a directed channel into parts with linear cost function. */
324373static void linearize_channel (const struct pay_parameters * params ,
@@ -348,9 +397,8 @@ static void linearize_channel(const struct pay_parameters *params,
348397 {
349398 set_capacity (& capacity [i ], params -> cap_fraction [i ]* (b - a ), & cap_on_capacity );
350399
351- cost [i ] = params -> cost_fraction [i ] * 1000
352- * amount_msat_ratio (params -> amount , params -> accuracy )
353- / (b - a );
400+ cost [i ] = params -> prob_cost_factor * params -> cost_fraction [i ] /
401+ (b - a );
354402 }
355403}
356404
@@ -867,6 +915,47 @@ get_flow_paths(const tal_t *ctx,
867915 return flows ;
868916}
869917
918+ /* Given a single path build a flow set. */
919+ static struct flow * *
920+ get_flow_singlepath (const tal_t * ctx , const struct pay_parameters * params ,
921+ const struct graph * graph , const struct gossmap * gossmap ,
922+ const struct node source , const struct node destination ,
923+ const u64 pay_amount , const struct arc * prev )
924+ {
925+ struct flow * * flows = tal_arr (ctx , struct flow * , 0 );
926+
927+ size_t length = 0 ;
928+
929+ for (u32 cur_idx = destination .idx ; cur_idx != source .idx ;) {
930+ assert (cur_idx != INVALID_INDEX );
931+ length ++ ;
932+ struct arc arc = prev [cur_idx ];
933+ struct node next = arc_tail (graph , arc );
934+ cur_idx = next .idx ;
935+ }
936+ struct flow * f = tal (ctx , struct flow );
937+ f -> path = tal_arr (f , const struct gossmap_chan * , length );
938+ f -> dirs = tal_arr (f , int , length );
939+
940+ for (u32 cur_idx = destination .idx ; cur_idx != source .idx ;) {
941+ int chandir ;
942+ u32 chanidx ;
943+ struct arc arc = prev [cur_idx ];
944+ arc_to_parts (arc , & chanidx , & chandir , NULL , NULL );
945+
946+ length -- ;
947+ f -> path [length ] = gossmap_chan_byidx (gossmap , chanidx );
948+ f -> dirs [length ] = chandir ;
949+
950+ struct node next = arc_tail (graph , arc );
951+ cur_idx = next .idx ;
952+ }
953+ if (!amount_msat_mul (& f -> delivers , params -> accuracy , pay_amount ))
954+ PANIC ("msat multiplication overflows" );
955+ tal_arr_expand (& flows , f );
956+ return flows ;
957+ }
958+
870959// TODO(eduardo): choose some default values for the minflow parameters
871960/* eduardo: I think it should be clear that this module deals with linear
872961 * flows, ie. base fees are not considered. Hence a flow along a path is
@@ -914,6 +1003,8 @@ struct flow **minflow(const tal_t *ctx,
9141003 /params -> cap_fraction [i ];
9151004 }
9161005
1006+ params -> prob_cost_factor =
1007+ 1000 * amount_msat_ratio (params -> amount , params -> accuracy );
9171008 params -> delay_feefactor = delay_feefactor ;
9181009 params -> base_fee_penalty = base_fee_penalty_estimate (amount );
9191010
@@ -1025,6 +1116,175 @@ static struct amount_msat linear_flows_cost(struct flow **flows,
10251116 return total ;
10261117}
10271118
1119+ /* Initialize the data vectors for the single-path solver. */
1120+ static void init_linear_network_single_path (
1121+ const tal_t * ctx , const struct pay_parameters * params , struct graph * * graph ,
1122+ double * * arc_prob_cost , s64 * * arc_fee_cost , s64 * * arc_capacity )
1123+ {
1124+ const size_t max_num_chans = gossmap_max_chan_idx (params -> rq -> gossmap );
1125+ const size_t max_num_arcs = max_num_chans * ARCS_PER_CHANNEL ;
1126+ const size_t max_num_nodes = gossmap_max_node_idx (params -> rq -> gossmap );
1127+
1128+ * graph = graph_new (ctx , max_num_nodes , max_num_arcs , ARC_DUAL_BITOFF );
1129+ * arc_prob_cost = tal_arr (ctx , double , max_num_arcs );
1130+ for (size_t i = 0 ; i < max_num_arcs ; ++ i )
1131+ (* arc_prob_cost )[i ] = DBL_MAX ;
1132+
1133+ * arc_fee_cost = tal_arr (ctx , s64 , max_num_arcs );
1134+ for (size_t i = 0 ; i < max_num_arcs ; ++ i )
1135+ (* arc_fee_cost )[i ] = INT64_MAX ;
1136+ * arc_capacity = tal_arrz (ctx , s64 , max_num_arcs );
1137+
1138+ /* We use this quantity to compute the cost of routing the entire
1139+ * amount, as opposed to the cost per unit of flow. */
1140+ const u64 pay_amount =
1141+ amount_msat_ratio_ceil (params -> amount , params -> accuracy );
1142+
1143+ const struct gossmap * gossmap = params -> rq -> gossmap ;
1144+
1145+ for (struct gossmap_node * node = gossmap_first_node (gossmap ); node ;
1146+ node = gossmap_next_node (gossmap , node )) {
1147+ const u32 node_id = gossmap_node_idx (gossmap , node );
1148+
1149+ for (size_t j = 0 ; j < node -> num_chans ; ++ j ) {
1150+ int half ;
1151+ const struct gossmap_chan * c =
1152+ gossmap_nth_chan (gossmap , node , j , & half );
1153+
1154+ if (!gossmap_chan_set (c , half ) ||
1155+ !c -> half [half ].enabled )
1156+ continue ;
1157+
1158+ /* If a channel cannot forward the total amount we don't
1159+ * use it. */
1160+ if (amount_msat_less (params -> amount ,
1161+ gossmap_chan_htlc_min (c , half )) ||
1162+ amount_msat_greater (params -> amount ,
1163+ gossmap_chan_htlc_max (c , half )))
1164+ continue ;
1165+
1166+ const u32 chan_id = gossmap_chan_idx (gossmap , c );
1167+
1168+ const struct gossmap_node * next =
1169+ gossmap_nth_node (gossmap , c , !half );
1170+
1171+ const u32 next_id = gossmap_node_idx (gossmap , next );
1172+
1173+ /* channel to self? */
1174+ if (node_id == next_id )
1175+ continue ;
1176+
1177+ struct arc arc =
1178+ arc_from_parts (chan_id , half , 0 , false);
1179+
1180+ graph_add_arc (* graph , arc , node_obj (node_id ),
1181+ node_obj (next_id ));
1182+
1183+ (* arc_capacity )[arc .idx ] = 1 ;
1184+ (* arc_prob_cost )[arc .idx ] =
1185+ params -> prob_cost_factor * (-1.0 ) *
1186+ log (channel_probability (params , c , half ,
1187+ params -> amount ));
1188+
1189+ (* arc_fee_cost )[arc .idx ] =
1190+ pay_amount *
1191+ linear_fee_cost (c -> half [half ].base_fee ,
1192+ c -> half [half ].proportional_fee ,
1193+ c -> half [half ].delay ,
1194+ params -> base_fee_penalty ,
1195+ params -> delay_feefactor );
1196+ }
1197+ }
1198+ }
1199+
1200+ /* Similar to minflow but computes routes that have a single path. */
1201+ struct flow * * single_path_flow (const tal_t * ctx , const struct route_query * rq ,
1202+ const struct gossmap_node * source ,
1203+ const struct gossmap_node * target ,
1204+ struct amount_msat amount , u32 mu ,
1205+ double delay_feefactor )
1206+ {
1207+ struct flow * * flow_paths ;
1208+ /* We allocate everything off this, and free it at the end,
1209+ * as we can be called multiple times without cleaning tmpctx! */
1210+ tal_t * working_ctx = tal (NULL , char );
1211+ struct pay_parameters * params = tal (working_ctx , struct pay_parameters );
1212+
1213+ params -> rq = rq ;
1214+ params -> source = source ;
1215+ params -> target = target ;
1216+ params -> amount = amount ;
1217+ /* for the single-path solver the accuracy does not detriment
1218+ * performance */
1219+ params -> accuracy = AMOUNT_MSAT (1000 );
1220+ params -> delay_feefactor = delay_feefactor ;
1221+ params -> base_fee_penalty = base_fee_penalty_estimate (amount );
1222+ params -> prob_cost_factor =
1223+ 1000 * amount_msat_ratio (params -> amount , params -> accuracy );
1224+
1225+ struct graph * graph ;
1226+ double * arc_prob_cost ;
1227+ s64 * arc_fee_cost ;
1228+ s64 * arc_capacity ;
1229+
1230+ init_linear_network_single_path (working_ctx , params , & graph ,
1231+ & arc_prob_cost , & arc_fee_cost ,
1232+ & arc_capacity );
1233+
1234+ const struct node dst = {.idx = gossmap_node_idx (rq -> gossmap , target )};
1235+ const struct node src = {.idx = gossmap_node_idx (rq -> gossmap , source )};
1236+
1237+ const size_t max_num_nodes = graph_max_num_nodes (graph );
1238+ const size_t max_num_arcs = graph_max_num_arcs (graph );
1239+
1240+ s64 * potential = tal_arrz (working_ctx , s64 , max_num_nodes );
1241+ s64 * distance = tal_arrz (working_ctx , s64 , max_num_nodes );
1242+ s64 * arc_cost = tal_arrz (working_ctx , s64 , max_num_arcs );
1243+ struct arc * prev = tal_arrz (working_ctx , struct arc , max_num_nodes );
1244+
1245+ combine_cost_function (working_ctx , graph , arc_prob_cost , arc_fee_cost ,
1246+ rq -> biases , mu , arc_cost );
1247+
1248+ /* We solve a linear cost flow problem. */
1249+ if (!dijkstra_path (working_ctx , graph , src , dst ,
1250+ /* prune = */ true, arc_capacity ,
1251+ /*threshold = */ 1 , arc_cost , potential , prev ,
1252+ distance )) {
1253+ /* This might fail if we are unable to find a suitable route, it
1254+ * doesn't mean the plugin is broken, that's why we LOG_INFORM. */
1255+ rq_log (tmpctx , rq , LOG_INFORM ,
1256+ "%s: could not find a feasible single path" , __func__ );
1257+ goto fail ;
1258+ }
1259+ const u64 pay_amount =
1260+ amount_msat_ratio_ceil (params -> amount , params -> accuracy );
1261+
1262+ /* We dissect the flow into payment routes.
1263+ * Actual amounts considering fees are computed for every
1264+ * channel in the routes. */
1265+ flow_paths = get_flow_singlepath (ctx , params , graph , rq -> gossmap ,
1266+ src , dst , pay_amount , prev );
1267+ if (!flow_paths ) {
1268+ rq_log (tmpctx , rq , LOG_BROKEN ,
1269+ "%s: failed to extract flow paths from the single-path "
1270+ "solution" ,
1271+ __func__ );
1272+ goto fail ;
1273+ }
1274+ if (tal_count (flow_paths ) != 1 ) {
1275+ rq_log (
1276+ tmpctx , rq , LOG_BROKEN ,
1277+ "%s: single-path solution returned a multi route solution" ,
1278+ __func__ );
1279+ goto fail ;
1280+ }
1281+ tal_free (working_ctx );
1282+ return flow_paths ;
1283+
1284+ fail :
1285+ tal_free (working_ctx );
1286+ return NULL ;
1287+ }
10281288
10291289const char * default_routes (const tal_t * ctx , struct route_query * rq ,
10301290 const struct gossmap_node * srcnode ,
0 commit comments