Skip to content

Commit 4b9f4bf

Browse files
committed
libplugin-pay: bias towards larger channels.
We bias by channel by up to 2x the fee; this should drive us towards larger channels. Signed-off-by: Rusty Russell <[email protected]> Changelog-Changed: Plugins: `pay` now biases towards larger channels, improving success probability.
1 parent 24bfb23 commit 4b9f4bf

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

plugins/libplugin-pay.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,55 @@ static bool payment_route_can_carry_even_disabled(const struct gossmap *map,
691691
return payment_route_check(map, c, dir, amount, p);
692692
}
693693

694+
/* Rene Pickhardt:
695+
*
696+
* Btw the linear term of the Taylor series of -log((c+1-x)/(c+1)) is 1/(c+1)
697+
* meaning that another suitable Weight for Dijkstra would be amt/(c+1) +
698+
* \mu*fee(amt) which is the linearized version which for small amounts and
699+
* suitable value of \mu should be good enough)
700+
*/
701+
static u64 capacity_bias(const struct gossmap *map,
702+
const struct gossmap_chan *c,
703+
int dir,
704+
struct amount_msat cost)
705+
{
706+
struct amount_msat fee;
707+
struct amount_sat capacity;
708+
709+
/* Overflow is pretty-much impossible, so ignore. */
710+
if (!amount_msat_fee(&fee, cost,
711+
c->half[dir].base_fee,
712+
c->half[dir].proportional_fee))
713+
return 0;
714+
715+
/* Can fail in theory if gossmap changed underneath. */
716+
if (!gossmap_chan_get_capacity(map, c, &capacity))
717+
return 0;
718+
719+
/* Assume we want \mu = 1/2 (i.e. capacity matters twice as much
720+
* as fees), we get: bias = 2 * fee * (amt / (c + 1)) */
721+
return 2
722+
* fee.millisatoshis /* Raw: complex math & laziness */
723+
* cost.millisatoshis /* Raw: complex math & laziness */
724+
/ (capacity.satoshis*1000 + 1); /* Raw: complex math & laziness */
725+
}
726+
727+
/* Prioritize costs over distance, but bias to larger channels. */
728+
static u64 route_score(u32 distance,
729+
struct amount_msat cost,
730+
struct amount_msat risk,
731+
int dir,
732+
const struct gossmap_chan *c)
733+
{
734+
u64 costs = cost.millisatoshis + risk.millisatoshis /* Raw: score */
735+
/* We use global_gossmap (can't still be NULL)
736+
* *without* which might change topology. */
737+
+ capacity_bias(global_gossmap, c, dir, cost);
738+
if (costs > 0xFFFFFFFF)
739+
costs = 0xFFFFFFFF;
740+
return costs;
741+
}
742+
694743
static struct route_hop *route(const tal_t *ctx,
695744
struct gossmap *gossmap,
696745
const struct gossmap_node *src,
@@ -712,14 +761,14 @@ static struct route_hop *route(const tal_t *ctx,
712761

713762
can_carry = payment_route_can_carry;
714763
dij = dijkstra(tmpctx, gossmap, dst, amount, riskfactor,
715-
can_carry, route_score_cheaper, p);
764+
can_carry, route_score, p);
716765
r = route_from_dijkstra(ctx, gossmap, dij, src, amount, final_delay);
717766
if (!r) {
718767
/* Try using disabled channels too */
719768
/* FIXME: is there somewhere we can annotate this for paystatus? */
720769
can_carry = payment_route_can_carry_even_disabled;
721770
dij = dijkstra(ctx, gossmap, dst, amount, riskfactor,
722-
can_carry, route_score_cheaper, p);
771+
can_carry, route_score, p);
723772
r = route_from_dijkstra(ctx, gossmap, dij, src,
724773
amount, final_delay);
725774
if (!r) {

plugins/test/run-route-overlong.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,6 @@ int main(void)
332332
int store_fd;
333333
struct payment *p;
334334
struct payment_modifier **mods;
335-
struct gossmap *gossmap;
336335
char gossip_version = GOSSIP_STORE_VERSION;
337336
char gossipfilename[] = "/tmp/run-route-overlong.XXXXXX";
338337

@@ -344,7 +343,7 @@ int main(void)
344343
assert(write(store_fd, &gossip_version, sizeof(gossip_version))
345344
== sizeof(gossip_version));
346345

347-
gossmap = gossmap_load(tmpctx, gossipfilename, NULL);
346+
global_gossmap = gossmap_load(tmpctx, gossipfilename, NULL);
348347

349348
for (size_t i = 0; i < NUM_NODES; i++) {
350349
struct privkey tmp;
@@ -383,7 +382,7 @@ int main(void)
383382
1 << i);
384383
}
385384

386-
assert(gossmap_refresh(gossmap, NULL));
385+
assert(gossmap_refresh(global_gossmap, NULL));
387386
for (size_t i = ROUTING_MAX_HOPS; i > 2; i--) {
388387
struct gossmap_node *dst, *src;
389388
struct route_hop *r;
@@ -392,9 +391,9 @@ int main(void)
392391
type_to_string(tmpctx, struct node_id, &ids[0]),
393392
type_to_string(tmpctx, struct node_id, &ids[NUM_NODES-1]));
394393

395-
src = gossmap_find_node(gossmap, &ids[0]);
396-
dst = gossmap_find_node(gossmap, &ids[NUM_NODES-1]);
397-
r = route(tmpctx, gossmap, src, dst, AMOUNT_MSAT(1000), 0, 0.0,
394+
src = gossmap_find_node(global_gossmap, &ids[0]);
395+
dst = gossmap_find_node(global_gossmap, &ids[NUM_NODES-1]);
396+
r = route(tmpctx, global_gossmap, src, dst, AMOUNT_MSAT(1000), 0, 0.0,
398397
i - 1, p, &errmsg);
399398
assert(r);
400399
/* FIXME: We naively fall back on shortest, rather

0 commit comments

Comments
 (0)