#include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifndef SUPERVERBOSE #define SUPERVERBOSE(...) #else #define SUPERVERBOSE_ENABLED 1 #endif /* How much do we deliver to destination using this set of routes */ struct amount_msat flowset_delivers(struct flow **flows) { struct amount_msat final = AMOUNT_MSAT(0); for (size_t i = 0; i < tal_count(flows); i++) { if (!amount_msat_accumulate(&final, flows[i]->delivers)) { child_err("Could not add flowsat %s to %s (%zu/%zu)", fmt_amount_msat(tmpctx, flows[i]->delivers), fmt_amount_msat(tmpctx, final), i, tal_count(flows)); } } return final; } /* Stolen whole-cloth from @Lagrang3 in renepay's flow.c. Wrong * because of htlc overhead in reservations! */ static double edge_probability(const struct route_query *rq, const struct short_channel_id_dir *scidd, struct amount_msat sent) { struct amount_msat numerator, denominator; struct amount_msat mincap, maxcap, additional; const struct gossmap_chan *c = gossmap_find_chan(rq->gossmap, &scidd->scid); get_constraints(rq, c, scidd->dir, &mincap, &maxcap); /* We add an extra per-htlc reservation for the *next* HTLC, so we "over-reserve" * on local channels. Undo that! */ additional = get_additional_per_htlc_cost(rq, scidd); if (!amount_msat_accumulate(&mincap, additional) || !amount_msat_accumulate(&maxcap, additional)) abort(); if (amount_msat_less_eq(sent, mincap)) return 1.0; else if (amount_msat_greater(sent, maxcap)) return 0.0; /* Linear probability: 1 - (spend - min) / (max - min) */ /* spend > mincap, from above. */ if (!amount_msat_sub(&numerator, sent, mincap)) abort(); /* This can only fail is maxcap was < mincap, * so we would be captured above */ if (!amount_msat_sub(&denominator, maxcap, mincap)) abort(); return 1.0 - amount_msat_ratio(numerator, denominator); } struct amount_msat flow_spend(const struct flow *flow) { const size_t pathlen = tal_count(flow->path); struct amount_msat spend = flow->delivers; for (int i = (int)pathlen - 1; i >= 0; i--) { const struct half_chan *h = flow_edge(flow, i); if (!amount_msat_add_fee(&spend, h->base_fee, h->proportional_fee)) { child_err("Could not add fee %u/%u to amount %s in %i/%zu", h->base_fee, h->proportional_fee, fmt_amount_msat(tmpctx, spend), i, pathlen); } } return spend; } struct amount_msat flow_fee(const struct flow *flow) { struct amount_msat spend = flow_spend(flow); struct amount_msat fee; if (!amount_msat_sub(&fee, spend, flow->delivers)) { child_err("Could not subtract %s from %s for fee", fmt_amount_msat(tmpctx, flow->delivers), fmt_amount_msat(tmpctx, spend)); } return fee; } struct amount_msat flowset_fee(struct flow **flows) { struct amount_msat fee = AMOUNT_MSAT(0); for (size_t i = 0; i < tal_count(flows); i++) { struct amount_msat this_fee = flow_fee(flows[i]); if (!amount_msat_accumulate(&fee, this_fee)) { child_err("Could not add %s to %s for flowset fee", fmt_amount_msat(tmpctx, this_fee), fmt_amount_msat(tmpctx, fee)); } } return fee; } /* Helper to access the half chan at flow index idx */ const struct half_chan *flow_edge(const struct flow *flow, size_t idx) { assert(flow); assert(idx < tal_count(flow->path)); return &flow->path[idx]->half[flow->dirs[idx]]; } /* Helper function to find the success_prob for a single flow * * IMPORTANT: flow->success_prob is misleading, because that's the prob. of * success provided that there are no other flows in the current MPP flow set. * */ double flow_probability(const struct flow *flow, const struct route_query *rq) { const size_t pathlen = tal_count(flow->path); struct amount_msat spend = flow->delivers; double prob = 1.0; for (int i = (int)pathlen - 1; i >= 0; i--) { const struct half_chan *h = flow_edge(flow, i); struct short_channel_id_dir scidd; scidd.scid = gossmap_chan_scid(rq->gossmap, flow->path[i]); scidd.dir = flow->dirs[i]; prob *= edge_probability(rq, &scidd, spend); if (!amount_msat_add_fee(&spend, h->base_fee, h->proportional_fee)) { child_err("Could not add fee %u/%u to amount %s in %i/%zu", h->base_fee, h->proportional_fee, fmt_amount_msat(tmpctx, spend), i, pathlen); } } return prob; } u64 flow_delay(const struct flow *flow) { u64 delay = 0; for (size_t i = 0; i < tal_count(flow->path); i++) delay += flow_edge(flow, i)->delay; return delay; } u64 flows_worst_delay(struct flow **flows) { u64 maxdelay = 0; for (size_t i = 0; i < tal_count(flows); i++) { u64 delay = flow_delay(flows[i]); if (delay > maxdelay) maxdelay = delay; } return maxdelay; } const char *fmt_flows_step_scid(const tal_t *ctx, const struct route_query *rq, const struct flow *flow, size_t i) { struct short_channel_id_dir scidd; scidd.scid = gossmap_chan_scid(rq->gossmap, flow->path[i]); scidd.dir = flow->dirs[i]; return fmt_short_channel_id_dir(ctx, &scidd); } const char *fmt_flow_full(const tal_t *ctx, const struct route_query *rq, const struct flow *flow) { struct amount_msat amt = flow->delivers; char *str = fmt_amount_msat(ctx, flow->delivers); for (int i = tal_count(flow->path) - 1; i >= 0; i--) { struct short_channel_id_dir scidd; struct amount_msat min, max; scidd.scid = gossmap_chan_scid(rq->gossmap, flow->path[i]); scidd.dir = flow->dirs[i]; if (!amount_msat_add_fee(&amt, flow->path[i]->half[scidd.dir].base_fee, flow->path[i]->half[scidd.dir].proportional_fee)) abort(); get_constraints(rq, flow->path[i], scidd.dir, &min, &max); tal_append_fmt(&str, " <- %s %s (cap=%s,fee=%u+%u,delay=%u)", fmt_amount_msat(tmpctx, amt), fmt_short_channel_id_dir(tmpctx, &scidd), fmt_amount_msat(tmpctx, max), flow->path[i]->half[scidd.dir].base_fee, flow->path[i]->half[scidd.dir].proportional_fee, flow->path[i]->half[scidd.dir].delay); } return str; } #ifndef SUPERVERBOSE_ENABLED #undef SUPERVERBOSE #endif