mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-21 22:31:48 +01:00
askrene: use refine step to calculate flowset probability.
Since we know the total reservations on each hop, we can more easily determine probabilities than using flowset_probability() which has to replicate this collision detection. We leave both in place for now, to check. The results are not identical, due to slightly different calculation methods. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
4b6a38fe0a
commit
5501e4b13d
4 changed files with 71 additions and 3 deletions
|
@ -16,6 +16,7 @@
|
|||
#include <common/json_stream.h>
|
||||
#include <common/route.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <plugins/askrene/askrene.h>
|
||||
#include <plugins/askrene/explain_failure.h>
|
||||
#include <plugins/askrene/flow.h>
|
||||
|
@ -336,6 +337,7 @@ static const char *get_routes(const tal_t *ctx,
|
|||
double delay_feefactor;
|
||||
u32 mu;
|
||||
const char *ret;
|
||||
double flowset_prob;
|
||||
|
||||
if (gossmap_refresh(askrene->gossmap, NULL)) {
|
||||
/* FIXME: gossmap_refresh callbacks to we can update in place */
|
||||
|
@ -488,7 +490,7 @@ too_expensive:
|
|||
* fees, so we try to adjust now. We could re-run MCF if this
|
||||
* fails, but failure basically never happens where payment is
|
||||
* still possible */
|
||||
ret = refine_with_fees_and_limits(ctx, rq, amount, &flows);
|
||||
ret = refine_with_fees_and_limits(ctx, rq, amount, &flows, &flowset_prob);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
|
@ -541,6 +543,10 @@ too_expensive:
|
|||
}
|
||||
|
||||
*probability = flowset_probability(flows, rq);
|
||||
if (fabs(*probability - flowset_prob) > 0.000001) {
|
||||
rq_log(tmpctx, rq, LOG_BROKEN, "Probability %f != expected %f",
|
||||
*probability, flowset_prob);
|
||||
}
|
||||
gossmap_remove_localmods(askrene->gossmap, localmods);
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -130,7 +130,15 @@ double flowset_probability(struct flow **flows,
|
|||
const struct amount_msat deliver = amounts[j];
|
||||
|
||||
get_constraints(rq, f->path[j], c_dir, &mincap, &maxcap);
|
||||
struct short_channel_id_dir scidd;
|
||||
scidd.scid = gossmap_chan_scid(rq->gossmap, f->path[j]);
|
||||
scidd.dir = c_dir;
|
||||
|
||||
rq_log(tmpctx, rq, LOG_DBG, "flow: edge_probability for %s: min=%s, max=%s, sent=%s",
|
||||
fmt_short_channel_id_dir(tmpctx, &scidd),
|
||||
fmt_amount_msat(tmpctx, mincap),
|
||||
fmt_amount_msat(tmpctx, maxcap),
|
||||
fmt_amount_msat(tmpctx, in_flight[c_idx].half[c_dir]));
|
||||
prob *= edge_probability(deliver, mincap, maxcap,
|
||||
in_flight[c_idx].half[c_dir]);
|
||||
|
||||
|
|
|
@ -408,11 +408,53 @@ static bool duplicate_one_flow(const struct route_query *rq,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* 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();
|
||||
|
||||
rq_log(tmpctx, rq, LOG_DBG, "refine: edge_probability for %s: min=%s, max=%s, sent=%s",
|
||||
fmt_short_channel_id_dir(tmpctx, scidd),
|
||||
fmt_amount_msat(tmpctx, mincap),
|
||||
fmt_amount_msat(tmpctx, maxcap),
|
||||
fmt_amount_msat(tmpctx, sent));
|
||||
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);
|
||||
}
|
||||
|
||||
const char *
|
||||
refine_with_fees_and_limits(const tal_t *ctx,
|
||||
struct route_query *rq,
|
||||
struct amount_msat deliver,
|
||||
struct flow ***flows)
|
||||
struct flow ***flows,
|
||||
double *flowset_probability)
|
||||
{
|
||||
struct reserve_hop *reservations = new_reservations(NULL, rq);
|
||||
struct amount_msat more_to_deliver;
|
||||
|
@ -536,6 +578,17 @@ refine_with_fees_and_limits(const tal_t *ctx,
|
|||
|
||||
ret = NULL;
|
||||
|
||||
/* Total flowset probability is now easily calculated given reservations
|
||||
* contains the total amounts through each channel (once we remove them) */
|
||||
destroy_reservations(reservations, get_askrene(rq->plugin));
|
||||
tal_add_destructor2(reservations, destroy_reservations, get_askrene(rq->plugin));
|
||||
|
||||
*flowset_probability = 1.0;
|
||||
for (size_t i = 0; i < tal_count(reservations); i++) {
|
||||
const struct reserve_hop *r = &reservations[i];
|
||||
*flowset_probability *= edge_probability(rq, &r->scidd, r->amount);
|
||||
}
|
||||
|
||||
out:
|
||||
tal_free(reservations);
|
||||
return ret;
|
||||
|
|
|
@ -21,5 +21,6 @@ const char *
|
|||
refine_with_fees_and_limits(const tal_t *ctx,
|
||||
struct route_query *rq,
|
||||
struct amount_msat deliver,
|
||||
struct flow ***flows);
|
||||
struct flow ***flows,
|
||||
double *flowset_probability);
|
||||
#endif /* LIGHTNING_PLUGINS_ASKRENE_REFINE_H */
|
||||
|
|
Loading…
Add table
Reference in a new issue