Skip to content

Commit 3a0d0da

Browse files
Lagrang3rustyrussell
authored andcommitted
askrene: refine: expose some of the refine API
that can be useful for us in the mcf.c main loop. Changelog-None Signed-off-by: Lagrang3 <[email protected]>
1 parent b479963 commit 3a0d0da

File tree

2 files changed

+150
-17
lines changed

2 files changed

+150
-17
lines changed

plugins/askrene/refine.c

Lines changed: 128 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <plugins/askrene/flow.h>
77
#include <plugins/askrene/refine.h>
88
#include <plugins/askrene/reserve.h>
9+
#include <string.h>
910

1011
/* Channel data for fast retrieval. */
1112
struct channel_data {
@@ -35,8 +36,8 @@ static void destroy_reservations(struct reserve_hop *rhops, struct askrene *askr
3536
reserve_remove(askrene->reserved, &rhops[i]);
3637
}
3738

38-
static struct reserve_hop *new_reservations(const tal_t *ctx,
39-
const struct route_query *rq)
39+
struct reserve_hop *new_reservations(const tal_t *ctx,
40+
const struct route_query *rq)
4041
{
4142
struct reserve_hop *rhops = tal_arr(ctx, struct reserve_hop, 0);
4243

@@ -108,9 +109,9 @@ static void subtract_reservation(struct reserve_hop **reservations,
108109
reserve_add(askrene->reserved, prev, rq->cmd->id);
109110
}
110111

111-
static void create_flow_reservations(const struct route_query *rq,
112-
struct reserve_hop **reservations,
113-
const struct flow *flow)
112+
void create_flow_reservations(const struct route_query *rq,
113+
struct reserve_hop **reservations,
114+
const struct flow *flow)
114115
{
115116
struct amount_msat msat;
116117

@@ -170,6 +171,32 @@ static void change_flow_delivers(const struct route_query *rq,
170171
create_flow_reservations(rq, reservations, flow);
171172
}
172173

174+
bool create_flow_reservations_verify(const struct route_query *rq,
175+
struct reserve_hop **reservations,
176+
const struct flow *flow)
177+
{
178+
struct amount_msat msat;
179+
msat = flow->delivers;
180+
for (int i = tal_count(flow->path) - 1; i >= 0; i--) {
181+
struct amount_msat known_min, known_max;
182+
const struct half_chan *h = flow_edge(flow, i);
183+
struct amount_msat amount_to_reserve = msat;
184+
struct short_channel_id_dir scidd;
185+
186+
get_scidd(rq->gossmap, flow, i, &scidd);
187+
get_constraints(rq, flow->path[i], flow->dirs[i], &known_min,
188+
&known_max);
189+
if (amount_msat_greater(amount_to_reserve, known_max))
190+
return false;
191+
192+
if (!amount_msat_add_fee(&msat, h->base_fee,
193+
h->proportional_fee))
194+
abort();
195+
}
196+
create_flow_reservations(rq, reservations, flow);
197+
return true;
198+
}
199+
173200
/* We use an fp16_t approximatin for htlc_max/min: this gets the exact value. */
174201
static struct amount_msat get_chan_htlc_max(const struct route_query *rq,
175202
const struct gossmap_chan *c,
@@ -846,6 +873,24 @@ static struct amount_msat remove_excess(struct flow **flows,
846873
return all_deliver;
847874
}
848875

876+
static void write_selected_flows(const tal_t *ctx, size_t *flows_index,
877+
struct flow ***flows)
878+
{
879+
struct flow **tmp_flows = tal_arr(ctx, struct flow *, 0);
880+
for (size_t i = 0; i < tal_count(flows_index); i++) {
881+
tal_arr_expand(&tmp_flows, (*flows)[flows_index[i]]);
882+
(*flows)[flows_index[i]] = NULL;
883+
}
884+
for (size_t i = 0; i < tal_count(*flows); i++) {
885+
(*flows)[i] = tal_free((*flows)[i]);
886+
}
887+
tal_resize(flows, 0);
888+
for (size_t i = 0; i < tal_count(tmp_flows); i++) {
889+
tal_arr_expand(flows, tmp_flows[i]);
890+
}
891+
tal_free(tmp_flows);
892+
}
893+
849894
/* FIXME: on failure return error message */
850895
const char *refine_flows(const tal_t *ctx, struct route_query *rq,
851896
struct amount_msat deliver, struct flow ***flows)
@@ -911,18 +956,7 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
911956
}
912957

913958
/* finally write the remaining flows */
914-
struct flow **tmp_flows = tal_arr(working_ctx, struct flow *, 0);
915-
for (size_t i = 0; i < tal_count(flows_index); i++) {
916-
tal_arr_expand(&tmp_flows, (*flows)[flows_index[i]]);
917-
(*flows)[flows_index[i]] = NULL;
918-
}
919-
for (size_t i = 0; i < tal_count(*flows); i++) {
920-
(*flows)[i] = tal_free((*flows)[i]);
921-
}
922-
tal_resize(flows, 0);
923-
for (size_t i = 0; i < tal_count(tmp_flows); i++) {
924-
tal_arr_expand(flows, tmp_flows[i]);
925-
}
959+
write_selected_flows(working_ctx, flows_index, flows);
926960

927961
tal_free(working_ctx);
928962
return NULL;
@@ -931,3 +965,80 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
931965
tal_free(working_ctx);
932966
return error_message;
933967
}
968+
969+
/* Order of flows according to path string */
970+
static int cmppath_flows(const size_t *a, const size_t *b, char **paths_str)
971+
{
972+
return strcmp(paths_str[*a], paths_str[*b]);
973+
}
974+
975+
void squash_flows(const tal_t *ctx, struct route_query *rq,
976+
struct flow ***flows)
977+
{
978+
const tal_t *working_ctx = tal(ctx, tal_t);
979+
size_t *flows_index = tal_arrz(working_ctx, size_t, tal_count(*flows));
980+
char **paths_str = tal_arrz(working_ctx, char *, tal_count(*flows));
981+
struct channel_data **channel_mpp_cache =
982+
new_channel_mpp_cache(working_ctx, rq, *flows);
983+
struct amount_msat *max_deliverable = tal_arrz(
984+
working_ctx, struct amount_msat, tal_count(channel_mpp_cache));
985+
986+
for (size_t i = 0; i < tal_count(flows_index); i++) {
987+
struct flow *flow = (*flows)[i];
988+
struct short_channel_id_dir scidd;
989+
flows_index[i] = i;
990+
paths_str[i] = tal_strdup(working_ctx, "");
991+
max_deliverable[i] = path_max_deliverable(channel_mpp_cache[i]);
992+
993+
for (size_t j = 0; j < tal_count(flow->path); j++) {
994+
scidd.scid =
995+
gossmap_chan_scid(rq->gossmap, flow->path[j]);
996+
scidd.dir = flow->dirs[j];
997+
tal_append_fmt(
998+
&paths_str[i], "%s%s", j > 0 ? "->" : "",
999+
fmt_short_channel_id_dir(working_ctx, &scidd));
1000+
}
1001+
}
1002+
1003+
asort(flows_index, tal_count(flows_index), cmppath_flows, paths_str);
1004+
for (size_t i = 0; i < tal_count(flows_index); i++) {
1005+
const size_t j = i + 1;
1006+
struct amount_msat combined;
1007+
struct amount_msat max = max_deliverable[flows_index[i]];
1008+
1009+
/* same path? We merge */
1010+
while (j < tal_count(flows_index) &&
1011+
cmppath_flows(&flows_index[i],
1012+
&flows_index[j],
1013+
paths_str) == 0) {
1014+
if (!amount_msat_add(
1015+
&combined, (*flows)[flows_index[i]]->delivers,
1016+
(*flows)[flows_index[j]]->delivers))
1017+
abort();
1018+
/* do we break any HTLC max limits */
1019+
if (amount_msat_greater(combined, max))
1020+
break;
1021+
(*flows)[flows_index[i]]->delivers = combined;
1022+
tal_arr_remove(&flows_index, j);
1023+
}
1024+
}
1025+
1026+
write_selected_flows(working_ctx, flows_index, flows);
1027+
1028+
tal_free(working_ctx);
1029+
}
1030+
1031+
double flows_probability(const tal_t *ctx, struct route_query *rq,
1032+
struct flow ***flows)
1033+
{
1034+
const tal_t *working_ctx = tal(ctx, tal_t);
1035+
struct reserve_hop *reservations = new_reservations(working_ctx, rq);
1036+
double probability = 1.0;
1037+
1038+
for (size_t i = 0; i < tal_count(*flows); i++) {
1039+
probability *= flow_probability((*flows)[i], rq);
1040+
create_flow_reservations(rq, &reservations, (*flows)[i]);
1041+
}
1042+
tal_free(working_ctx);
1043+
return probability;
1044+
}

plugins/askrene/refine.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ struct route_query;
77
struct amount_msat;
88
struct flow;
99

10+
struct reserve_hop *new_reservations(const tal_t *ctx,
11+
const struct route_query *rq);
12+
13+
void create_flow_reservations(const struct route_query *rq,
14+
struct reserve_hop **reservations,
15+
const struct flow *flow);
16+
1017
/* We got an answer from min-cost-flow, but we now need to:
1118
* 1. Add fixup exact delivery amounts since MCF deals in larger granularity than msat.
1219
* 2. Add fees which accumulate through the route.
@@ -24,8 +31,23 @@ refine_with_fees_and_limits(const tal_t *ctx,
2431
struct flow ***flows,
2532
double *flowset_probability);
2633

34+
/* create flow reservations, but first verify that the flow indeeds fits in the
35+
* liquidity constraints. Takes into account reservations that include per HTLC
36+
* extra amounts to pay for onchain fees. */
37+
bool create_flow_reservations_verify(const struct route_query *rq,
38+
struct reserve_hop **reservations,
39+
const struct flow *flow);
40+
2741
/* Modify flows to meet HTLC min/max requirements.
2842
* It takes into account the exact value of the fees expected at each hop. */
2943
const char *refine_flows(const tal_t *ctx, struct route_query *rq,
3044
struct amount_msat deliver, struct flow ***flows);
45+
46+
/* Duplicated flows are merged into one. This saves in base fee and HTLC fees.
47+
*/
48+
void squash_flows(const tal_t *ctx, struct route_query *rq,
49+
struct flow ***flows);
50+
51+
double flows_probability(const tal_t *ctx, struct route_query *rq,
52+
struct flow ***flows);
3153
#endif /* LIGHTNING_PLUGINS_ASKRENE_REFINE_H */

0 commit comments

Comments
 (0)