|
2 | 2 | #include <assert.h> |
3 | 3 | #include <ccan/asort/asort.h> |
4 | 4 | #include <ccan/bitmap/bitmap.h> |
| 5 | +#include <ccan/err/err.h> |
5 | 6 | #include <ccan/list/list.h> |
6 | 7 | #include <ccan/tal/str/str.h> |
7 | 8 | #include <ccan/tal/tal.h> |
|
159 | 160 | * |
160 | 161 | * */ |
161 | 162 |
|
| 163 | +#define PANIC(message) \ |
| 164 | + errx(1, "Panic in function %s line %d: %s", __func__, __LINE__, \ |
| 165 | + message); |
| 166 | + |
162 | 167 | #define PARTS_BITS 2 |
163 | 168 | #define CHANNEL_PARTS (1 << PARTS_BITS) |
164 | 169 |
|
@@ -319,6 +324,28 @@ static void set_capacity(s64 *capacity, u64 value, u64 *cap_on_capacity) |
319 | 324 | *cap_on_capacity -= *capacity; |
320 | 325 | } |
321 | 326 |
|
| 327 | +/* FIXME: unit test this */ |
| 328 | +/* The probability of forwarding a payment amount given a high and low liquidity |
| 329 | + * bounds. |
| 330 | + * @low: the liquidity is known to be greater or equal than "low" |
| 331 | + * @high: the liquidity is known to be less than "high" |
| 332 | + * @amount: how much is required to forward */ |
| 333 | +static double pickhardt_richter_probability(struct amount_msat low, |
| 334 | + struct amount_msat high, |
| 335 | + struct amount_msat amount) |
| 336 | +{ |
| 337 | + struct amount_msat all_states, good_states; |
| 338 | + if (amount_msat_greater_eq(amount, high)) |
| 339 | + return 0.0; |
| 340 | + if (!amount_msat_sub(&amount, amount, low)) |
| 341 | + return 1.0; |
| 342 | + if (!amount_msat_sub(&all_states, high, low)) |
| 343 | + PANIC("we expect high > low"); |
| 344 | + if (!amount_msat_sub(&good_states, all_states, amount)) |
| 345 | + PANIC("we expect high > amount"); |
| 346 | + return amount_msat_ratio(good_states, all_states); |
| 347 | +} |
| 348 | + |
322 | 349 | // TODO(eduardo): unit test this |
323 | 350 | /* Split a directed channel into parts with linear cost function. */ |
324 | 351 | static void linearize_channel(const struct pay_parameters *params, |
@@ -867,6 +894,46 @@ get_flow_paths(const tal_t *ctx, |
867 | 894 | return flows; |
868 | 895 | } |
869 | 896 |
|
| 897 | +/* Given a single path build a flow set. */ |
| 898 | +static struct flow ** |
| 899 | +get_flow_singlepath(const tal_t *ctx, const struct pay_parameters *params, |
| 900 | + const struct graph *graph, const struct gossmap *gossmap, |
| 901 | + const struct node source, const struct node destination, |
| 902 | + const u64 pay_amount, const struct arc *prev) |
| 903 | +{ |
| 904 | + struct flow **flows = tal_arr(ctx, struct flow *, 0); |
| 905 | + |
| 906 | + size_t length = 0; |
| 907 | + |
| 908 | + for (u32 cur_idx = destination.idx; cur_idx != source.idx;) { |
| 909 | + assert(cur_idx != INVALID_INDEX); |
| 910 | + length++; |
| 911 | + struct arc arc = prev[cur_idx]; |
| 912 | + struct node next = arc_tail(graph, arc); |
| 913 | + cur_idx = next.idx; |
| 914 | + } |
| 915 | + struct flow *f = tal(ctx, struct flow); |
| 916 | + f->path = tal_arr(f, const struct gossmap_chan *, length); |
| 917 | + f->dirs = tal_arr(f, int, length); |
| 918 | + |
| 919 | + for (u32 cur_idx = destination.idx; cur_idx != source.idx;) { |
| 920 | + int chandir; |
| 921 | + u32 chanidx; |
| 922 | + struct arc arc = prev[cur_idx]; |
| 923 | + arc_to_parts(arc, &chanidx, &chandir, NULL, NULL); |
| 924 | + |
| 925 | + length--; |
| 926 | + f->path[length] = gossmap_chan_byidx(gossmap, chanidx); |
| 927 | + f->dirs[length] = chandir; |
| 928 | + |
| 929 | + struct node next = arc_tail(graph, arc); |
| 930 | + cur_idx = next.idx; |
| 931 | + } |
| 932 | + f->delivers = params->amount; |
| 933 | + tal_arr_expand(&flows, f); |
| 934 | + return flows; |
| 935 | +} |
| 936 | + |
870 | 937 | // TODO(eduardo): choose some default values for the minflow parameters |
871 | 938 | /* eduardo: I think it should be clear that this module deals with linear |
872 | 939 | * flows, ie. base fees are not considered. Hence a flow along a path is |
@@ -1025,6 +1092,186 @@ static struct amount_msat linear_flows_cost(struct flow **flows, |
1025 | 1092 | return total; |
1026 | 1093 | } |
1027 | 1094 |
|
| 1095 | +/* Initialize the data vectors for the single-path solver. */ |
| 1096 | +static void init_linear_network_single_path( |
| 1097 | + const tal_t *ctx, const struct pay_parameters *params, struct graph **graph, |
| 1098 | + double **arc_prob_cost, s64 **arc_fee_cost, s64 **arc_capacity) |
| 1099 | +{ |
| 1100 | + const size_t max_num_chans = gossmap_max_chan_idx(params->rq->gossmap); |
| 1101 | + const size_t max_num_arcs = max_num_chans * ARCS_PER_CHANNEL; |
| 1102 | + const size_t max_num_nodes = gossmap_max_node_idx(params->rq->gossmap); |
| 1103 | + |
| 1104 | + *graph = graph_new(ctx, max_num_nodes, max_num_arcs, ARC_DUAL_BITOFF); |
| 1105 | + *arc_prob_cost = tal_arr(ctx, double, max_num_arcs); |
| 1106 | + for (size_t i = 0; i < max_num_arcs; ++i) |
| 1107 | + (*arc_prob_cost)[i] = DBL_MAX; |
| 1108 | + |
| 1109 | + *arc_fee_cost = tal_arr(ctx, s64, max_num_arcs); |
| 1110 | + for (size_t i = 0; i < max_num_arcs; ++i) |
| 1111 | + (*arc_fee_cost)[i] = INT64_MAX; |
| 1112 | + *arc_capacity = tal_arrz(ctx, s64, max_num_arcs); |
| 1113 | + |
| 1114 | + const struct gossmap *gossmap = params->rq->gossmap; |
| 1115 | + |
| 1116 | + for (struct gossmap_node *node = gossmap_first_node(gossmap); node; |
| 1117 | + node = gossmap_next_node(gossmap, node)) { |
| 1118 | + const u32 node_id = gossmap_node_idx(gossmap, node); |
| 1119 | + |
| 1120 | + for (size_t j = 0; j < node->num_chans; ++j) { |
| 1121 | + int half; |
| 1122 | + const struct gossmap_chan *c = |
| 1123 | + gossmap_nth_chan(gossmap, node, j, &half); |
| 1124 | + struct amount_msat mincap, maxcap; |
| 1125 | + |
| 1126 | + if (!gossmap_chan_set(c, half) || |
| 1127 | + !c->half[half].enabled) |
| 1128 | + continue; |
| 1129 | + |
| 1130 | + /* If a channel cannot forward the total amount we don't |
| 1131 | + * use it. */ |
| 1132 | + if (amount_msat_less(params->amount, |
| 1133 | + gossmap_chan_htlc_min(c, half)) || |
| 1134 | + amount_msat_greater(params->amount, |
| 1135 | + gossmap_chan_htlc_max(c, half))) |
| 1136 | + continue; |
| 1137 | + |
| 1138 | + get_constraints(params->rq, c, half, &mincap, &maxcap); |
| 1139 | + /* Assume if min > max, min is wrong */ |
| 1140 | + if (amount_msat_greater(mincap, maxcap)) |
| 1141 | + mincap = maxcap; |
| 1142 | + /* It is preferable to work on 1msat past the known |
| 1143 | + * bound. */ |
| 1144 | + if (!amount_msat_accumulate(&maxcap, amount_msat(1))) |
| 1145 | + PANIC("maxcap + 1msat overflows"); |
| 1146 | + |
| 1147 | + /* If amount is greater than the known liquidity upper |
| 1148 | + * bound we get infinite probability cost. */ |
| 1149 | + if (amount_msat_greater_eq(params->amount, maxcap)) |
| 1150 | + continue; |
| 1151 | + |
| 1152 | + const u32 chan_id = gossmap_chan_idx(gossmap, c); |
| 1153 | + |
| 1154 | + const struct gossmap_node *next = |
| 1155 | + gossmap_nth_node(gossmap, c, !half); |
| 1156 | + |
| 1157 | + const u32 next_id = gossmap_node_idx(gossmap, next); |
| 1158 | + |
| 1159 | + /* channel to self? */ |
| 1160 | + if (node_id == next_id) |
| 1161 | + continue; |
| 1162 | + |
| 1163 | + struct arc arc = |
| 1164 | + arc_from_parts(chan_id, half, 0, false); |
| 1165 | + |
| 1166 | + graph_add_arc(*graph, arc, node_obj(node_id), |
| 1167 | + node_obj(next_id)); |
| 1168 | + |
| 1169 | + (*arc_capacity)[arc.idx] = 1; |
| 1170 | + (*arc_prob_cost)[arc.idx] = |
| 1171 | + (-1.0) * log(pickhardt_richter_probability( |
| 1172 | + mincap, maxcap, params->amount)); |
| 1173 | + |
| 1174 | + struct amount_msat fee; |
| 1175 | + if (!amount_msat_fee(&fee, params->amount, |
| 1176 | + c->half[half].base_fee, |
| 1177 | + c->half[half].proportional_fee)) |
| 1178 | + PANIC("fee overflow"); |
| 1179 | + u32 fee_msat; |
| 1180 | + if (!amount_msat_to_u32(fee, &fee_msat)) |
| 1181 | + PANIC("fee does not fit in u32"); |
| 1182 | + (*arc_fee_cost)[arc.idx] = |
| 1183 | + fee_msat + |
| 1184 | + params->delay_feefactor * c->half[half].delay; |
| 1185 | + } |
| 1186 | + } |
| 1187 | +} |
| 1188 | + |
| 1189 | +/* Similar to minflow but computes routes that have a single path. */ |
| 1190 | +struct flow **single_path_flow(const tal_t *ctx, const struct route_query *rq, |
| 1191 | + const struct gossmap_node *source, |
| 1192 | + const struct gossmap_node *target, |
| 1193 | + struct amount_msat amount, u32 mu, |
| 1194 | + double delay_feefactor) |
| 1195 | +{ |
| 1196 | + struct flow **flow_paths; |
| 1197 | + /* We allocate everything off this, and free it at the end, |
| 1198 | + * as we can be called multiple times without cleaning tmpctx! */ |
| 1199 | + tal_t *working_ctx = tal(NULL, char); |
| 1200 | + struct pay_parameters *params = tal(working_ctx, struct pay_parameters); |
| 1201 | + |
| 1202 | + params->rq = rq; |
| 1203 | + params->source = source; |
| 1204 | + params->target = target; |
| 1205 | + params->amount = amount; |
| 1206 | + /* for the single-path solver the accuracy does not detriment |
| 1207 | + * performance */ |
| 1208 | + params->accuracy = amount; |
| 1209 | + params->delay_feefactor = delay_feefactor; |
| 1210 | + params->base_fee_penalty = base_fee_penalty_estimate(amount); |
| 1211 | + |
| 1212 | + struct graph *graph; |
| 1213 | + double *arc_prob_cost; |
| 1214 | + s64 *arc_fee_cost; |
| 1215 | + s64 *arc_capacity; |
| 1216 | + |
| 1217 | + init_linear_network_single_path(working_ctx, params, &graph, |
| 1218 | + &arc_prob_cost, &arc_fee_cost, |
| 1219 | + &arc_capacity); |
| 1220 | + |
| 1221 | + const struct node dst = {.idx = gossmap_node_idx(rq->gossmap, target)}; |
| 1222 | + const struct node src = {.idx = gossmap_node_idx(rq->gossmap, source)}; |
| 1223 | + |
| 1224 | + const size_t max_num_nodes = graph_max_num_nodes(graph); |
| 1225 | + const size_t max_num_arcs = graph_max_num_arcs(graph); |
| 1226 | + |
| 1227 | + s64 *potential = tal_arrz(working_ctx, s64, max_num_nodes); |
| 1228 | + s64 *distance = tal_arrz(working_ctx, s64, max_num_nodes); |
| 1229 | + s64 *arc_cost = tal_arrz(working_ctx, s64, max_num_arcs); |
| 1230 | + struct arc *prev = tal_arrz(working_ctx, struct arc, max_num_nodes); |
| 1231 | + |
| 1232 | + combine_cost_function(working_ctx, graph, arc_prob_cost, arc_fee_cost, |
| 1233 | + rq->biases, mu, arc_cost); |
| 1234 | + |
| 1235 | + /* We solve a linear cost flow problem. */ |
| 1236 | + if (!dijkstra_path(working_ctx, graph, src, dst, |
| 1237 | + /* prune = */ true, arc_capacity, |
| 1238 | + /*threshold = */ 1, arc_cost, potential, prev, |
| 1239 | + distance)) { |
| 1240 | + /* This might fail if we are unable to find a suitable route, it |
| 1241 | + * doesn't mean the plugin is broken, that's why we LOG_INFORM. */ |
| 1242 | + rq_log(tmpctx, rq, LOG_INFORM, |
| 1243 | + "%s: could not find a feasible single path", __func__); |
| 1244 | + goto fail; |
| 1245 | + } |
| 1246 | + const u64 pay_amount = |
| 1247 | + amount_msat_ratio_ceil(params->amount, params->accuracy); |
| 1248 | + |
| 1249 | + /* We dissect the flow into payment routes. |
| 1250 | + * Actual amounts considering fees are computed for every |
| 1251 | + * channel in the routes. */ |
| 1252 | + flow_paths = get_flow_singlepath(ctx, params, graph, rq->gossmap, |
| 1253 | + src, dst, pay_amount, prev); |
| 1254 | + if (!flow_paths) { |
| 1255 | + rq_log(tmpctx, rq, LOG_BROKEN, |
| 1256 | + "%s: failed to extract flow paths from the single-path " |
| 1257 | + "solution", |
| 1258 | + __func__); |
| 1259 | + goto fail; |
| 1260 | + } |
| 1261 | + if (tal_count(flow_paths) != 1) { |
| 1262 | + rq_log( |
| 1263 | + tmpctx, rq, LOG_BROKEN, |
| 1264 | + "%s: single-path solution returned a multi route solution", |
| 1265 | + __func__); |
| 1266 | + goto fail; |
| 1267 | + } |
| 1268 | + tal_free(working_ctx); |
| 1269 | + return flow_paths; |
| 1270 | + |
| 1271 | +fail: |
| 1272 | + tal_free(working_ctx); |
| 1273 | + return NULL; |
| 1274 | +} |
1028 | 1275 |
|
1029 | 1276 | const char *default_routes(const tal_t *ctx, struct route_query *rq, |
1030 | 1277 | const struct gossmap_node *srcnode, |
|
0 commit comments