Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion plugins/askrene/askrene.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,23 @@ static void add_localchan(struct gossmap_localmods *mods,
if (!layer_find_local_channel(info->local_layer, scidd->scid))
layer_add_local_channel(info->local_layer,
self, peer, scidd->scid, capacity_msat);
else {
/* FIXME: In theory if we know with 100% certainty the liquidity of
* one half we can deduce with 100% certainty the liquidity of
* the other half. Inserting both as separate channels
* constraints shouldn't do no harm, at most it is redundant.
* However, our model doesn't (yet) know how to treat channel
* reserves therefore including both halves produces incoherent
* liquidity bounds. eg. a channel with capacity 100k sat,
* initially opened by us, listpeerchannels would say we can
* spend 100k - reserves, assuming this is 95k sat, askrene
* would think that there are 5k sat available in the opposite
* direction, or believe that our min/max equals exactly 100k
* (not 95k) because the other side has 0 sat spendable.
* We avoid these troubles by submitting only our half of the
* channel to local_layer. */
return;
}
layer_add_update_channel(info->local_layer, scidd,
&enabled,
&htlcmin, &htlcmax,
Expand Down Expand Up @@ -820,7 +837,8 @@ static void add_localchan(struct gossmap_localmods *mods,
/* can't send more than expendable and no more than max_total_htlc */
struct amount_msat max_msat = amount_msat_min(spendable, max_total_htlc);
/* Known capacity on local channels (ts = max) */
layer_add_constraint(info->local_layer, scidd, UINT64_MAX, &max_msat, &max_msat);
layer_add_constraint(info->local_layer, scidd, UINT64_MAX, &max_msat, NULL);
layer_add_constraint(info->local_layer, scidd, UINT64_MAX, NULL, &max_msat);
}

static struct command_result *
Expand Down
2 changes: 2 additions & 0 deletions plugins/askrene/child/child.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <ccan/json_out/json_out.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/tal/str/str.h>
#include <common/clock_time.h>
#include <common/json_stream.h>
#include <common/node_id.h>
#include <common/utils.h>
Expand Down Expand Up @@ -204,6 +205,7 @@ static struct route_query *new_route_query(const tal_t *ctx,
rq->disabled_chans =
tal_arrz(rq, bitmap,
2 * BITMAP_NWORDS(gossmap_max_chan_idx(gossmap)));
rq->current_unixtime = clock_time().ts.tv_sec;

return rq;
}
Expand Down
37 changes: 34 additions & 3 deletions plugins/askrene/child/mcf.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,25 @@
// cost function arcs.
static const double CHANNEL_PIVOTS[]={0,0.5,0.8,0.95};

/* MCF preserves flow at intermediate hops, therefore fees do not contribute to
* flows or flows costs. We can exceed capacity limits once fees are added
* and/or discover very high probability costs triggered by them. To mitigate
* this we scale down the min/max limits by this factor assuming a worst case
* fee of 1% of the flow amount. This works because multiplying the flow by g
* produces the same cost than multiplying the min/max bounds by 1/g.
*
* We want a new cost function
* C'(x) = C(x + fees) where x+fees = x*(1+0.01)= x*g
*
* C'(x) = C(x*g) =
* case x*g <= a, same as x <= a/g: 0
* case x*g >= b, same as x >= b/g: infinity
* case a<=x*g<b, same as a/g<=x<b/g: -log(1-(x*g-a)/(b-a)) = -log(1-(x-a/g)/(b/g-a/g))
* */
/* FIXME: This could prevent us from finding flows that fit tightly through
* channel capacities. */
static const double FLOW_FEE_ADJUSTMENT = 1.01;

static const s64 INFINITE = INT64_MAX;
static const s64 MU_MAX = 100;

Expand Down Expand Up @@ -338,9 +357,9 @@ static bool channel_is_available(const struct route_query *rq,
* @low: the liquidity is known to be greater or equal than "low"
* @high: the liquidity is known to be less than "high"
* @amount: how much is required to forward */
static double pickhardt_richter_probability(struct amount_msat low,
struct amount_msat high,
struct amount_msat amount)
double pickhardt_richter_probability(struct amount_msat low,
struct amount_msat high,
struct amount_msat amount)
{
struct amount_msat all_states, good_states;
if (amount_msat_greater_eq(amount, high))
Expand Down Expand Up @@ -369,6 +388,18 @@ static void linearize_channel(const struct pay_parameters *params,
if (amount_msat_greater(mincap, maxcap))
mincap = maxcap;

/* Allow space for fees at 1% */
if (!amount_msat_scale(&mincap, mincap, 1 / FLOW_FEE_ADJUSTMENT)) {
child_log(tmpctx, LOG_UNUSUAL,
"%s: Couldn't scale down mincap=%s by %lf", __func__,
fmt_amount_msat(tmpctx, mincap), FLOW_FEE_ADJUSTMENT);
}
if (!amount_msat_scale(&maxcap, maxcap, 1 / FLOW_FEE_ADJUSTMENT)) {
child_log(tmpctx, LOG_UNUSUAL,
"%s: Couldn't scale down maxcap=%s by %lf", __func__,
fmt_amount_msat(tmpctx, maxcap), FLOW_FEE_ADJUSTMENT);
}

u64 a = amount_msat_ratio_floor(mincap, params->accuracy),
b = 1 + amount_msat_ratio_floor(maxcap, params->accuracy);

Expand Down
10 changes: 10 additions & 0 deletions plugins/askrene/child/mcf.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <common/gossmap.h>
#include <common/jsonrpc_errors.h>

struct flow;
struct route_query;

/* A wrapper to the min. cost flow solver that actually takes into consideration
Expand All @@ -33,4 +34,13 @@ const char *single_path_routes(const tal_t *ctx, struct route_query *rq,
double *probability,
enum jsonrpc_errcode *ecode);

/* The probability of forwarding a payment amount given a high and low liquidity
* bounds.
* @low: the liquidity is known to be greater or equal than "low"
* @high: the liquidity is known to be less than "high"
* @amount: how much is required to forward */
double pickhardt_richter_probability(struct amount_msat low,
struct amount_msat high,
struct amount_msat amount);

#endif /* LIGHTNING_PLUGINS_ASKRENE_CHILD_MCF_H */
Loading
Loading