2023-12-06 21:14:05 +01:00
|
|
|
#include "config.h"
|
|
|
|
#include <ccan/err/err.h>
|
|
|
|
#include <common/gossmap.h>
|
|
|
|
#include <common/gossmods_listpeerchannels.h>
|
|
|
|
#include <common/node_id.h>
|
|
|
|
#include <plugins/libplugin.h>
|
|
|
|
|
|
|
|
void gossmod_add_localchan(struct gossmap_localmods *mods,
|
|
|
|
const struct node_id *self,
|
|
|
|
const struct node_id *peer,
|
|
|
|
const struct short_channel_id_dir *scidd,
|
2024-03-18 08:31:42 +01:00
|
|
|
struct amount_msat htlcmin,
|
|
|
|
struct amount_msat htlcmax,
|
|
|
|
struct amount_msat spendable,
|
2023-12-06 21:14:05 +01:00
|
|
|
struct amount_msat fee_base,
|
|
|
|
u32 fee_proportional,
|
|
|
|
u32 cltv_delta,
|
|
|
|
bool enabled,
|
|
|
|
const char *buf UNUSED,
|
|
|
|
const jsmntok_t *chantok UNUSED,
|
|
|
|
void *cbarg UNUSED)
|
|
|
|
{
|
2024-03-18 08:31:42 +01:00
|
|
|
struct amount_msat min = htlcmin, max = htlcmax;
|
|
|
|
|
|
|
|
if (amount_msat_less(spendable, max))
|
|
|
|
max = spendable;
|
|
|
|
|
2023-12-06 21:14:05 +01:00
|
|
|
/* FIXME: features? */
|
2024-03-20 02:59:51 +01:00
|
|
|
gossmap_local_addchan(mods, self, peer, scidd->scid, NULL);
|
2023-12-06 21:14:05 +01:00
|
|
|
|
2024-03-20 02:59:51 +01:00
|
|
|
gossmap_local_updatechan(mods, scidd->scid, min, max,
|
2023-12-06 21:14:05 +01:00
|
|
|
fee_base.millisatoshis, /* Raw: gossmap */
|
|
|
|
fee_proportional,
|
|
|
|
cltv_delta,
|
|
|
|
enabled,
|
|
|
|
scidd->dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct gossmap_localmods *
|
|
|
|
gossmods_from_listpeerchannels_(const tal_t *ctx,
|
|
|
|
const struct node_id *self,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *toks,
|
pay: ignore fees on our own channels when determining routing.
I noticed that run-route-infloop chose some worse-looking paths after
routing was fixed, eg the second node:
Before:
Destination node, success, probability, hops, fees, cltv, scid...
02b3aa1e4ed31be83cca4bd367b2c01e39502cb25e282a9b4520ad376a1ba0a01a,1,0.991856,2,1004,40,2572260x39x0/1,2131897x45x0/0
After:
Destination node, success, probability, hops, fees, cltv, scid...
02b3aa1e4ed31be83cca4bd367b2c01e39502cb25e282a9b4520ad376a1ba0a01a,1,0.954540,3,1046,46,2570715x21x0/1,2346882x26x14/1,2131897x45x0/0
This is because although the final costs don't reflect it, routing was taking
into account local channels, and 2572260x39x0/1 has a base fee of 2970.
There's an easy fix: when we the pay plugin creates localmods for our
gossip graph, add all local channels with delay and fees equal to 0.
We do the same thing in our unit test. This improves things across
the board:
Linear success probability (when found): min-max(mean +/- stddev)
Before: 0.487040-0.999543(0.952548+/-0.075)
After: 0.486985-0.999750(0.975978+/-0.053)
Hops:
Before: 1-5(2.98374+/-0.77)
After: 1-5(2.09593+/-0.63)
Fees:
Before: 0-50848(922.457+/-2.7e+03)
After: 0-50041(861.621+/-2.7e+03)
Delay (blocks):
Before: 0-196(65.8081+/-60)
After: 0-190(60.3285+/-60)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: Plugins: `pay` route algorithm doesn't bias against our own "expensive" channels any more.
2024-03-07 03:56:58 +01:00
|
|
|
bool zero_rates,
|
2023-12-06 21:14:05 +01:00
|
|
|
void (*cb)(struct gossmap_localmods *mods,
|
|
|
|
const struct node_id *self,
|
|
|
|
const struct node_id *peer,
|
|
|
|
const struct short_channel_id_dir *scidd,
|
2024-03-18 08:31:42 +01:00
|
|
|
struct amount_msat htlcmin,
|
|
|
|
struct amount_msat htlcmax,
|
|
|
|
struct amount_msat sr_able,
|
2023-12-06 21:14:05 +01:00
|
|
|
struct amount_msat fee_base,
|
|
|
|
u32 fee_proportional,
|
|
|
|
u32 cltv_delta,
|
|
|
|
bool enabled,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *chantok,
|
|
|
|
void *cbarg),
|
|
|
|
void *cbarg)
|
|
|
|
{
|
|
|
|
struct gossmap_localmods *mods = gossmap_localmods_new(ctx);
|
|
|
|
const jsmntok_t *channels, *channel;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
channels = json_get_member(buf, toks, "channels");
|
|
|
|
json_for_each_arr(i, channel, channels) {
|
|
|
|
struct short_channel_id_dir scidd;
|
|
|
|
struct short_channel_id alias;
|
|
|
|
bool enabled;
|
|
|
|
struct node_id dst;
|
|
|
|
struct amount_msat spendable, receivable, fee_base[NUM_SIDES], htlc_min[NUM_SIDES], htlc_max[NUM_SIDES];
|
|
|
|
u32 fee_proportional[NUM_SIDES], cltv_delta[NUM_SIDES];
|
|
|
|
const char *state, *err;
|
|
|
|
|
|
|
|
/* scid/direction and alias may not exist. */
|
|
|
|
scidd.scid.u64 = 0;
|
|
|
|
alias.u64 = 0;
|
|
|
|
|
|
|
|
/* We do this to note if we have no remote update. */
|
|
|
|
fee_proportional[REMOTE] = -1U;
|
|
|
|
|
|
|
|
err = json_scan(tmpctx, buf, channel,
|
|
|
|
"{short_channel_id?:%,"
|
|
|
|
"direction?:%,"
|
|
|
|
"spendable_msat?:%,"
|
|
|
|
"receivable_msat?:%,"
|
|
|
|
"peer_connected:%,"
|
|
|
|
"state:%,"
|
|
|
|
"peer_id:%,"
|
|
|
|
"updates?:{"
|
|
|
|
"local"
|
|
|
|
":{fee_base_msat:%,"
|
|
|
|
"fee_proportional_millionths:%,"
|
|
|
|
"htlc_minimum_msat:%,"
|
|
|
|
"htlc_maximum_msat:%,"
|
|
|
|
"cltv_expiry_delta:%},"
|
|
|
|
"remote?"
|
|
|
|
":{fee_base_msat:%,"
|
|
|
|
"fee_proportional_millionths:%,"
|
|
|
|
"htlc_minimum_msat:%,"
|
|
|
|
"htlc_maximum_msat:%,"
|
|
|
|
"cltv_expiry_delta:%}},"
|
|
|
|
"alias?:{local:%}}",
|
|
|
|
JSON_SCAN(json_to_short_channel_id, &scidd.scid),
|
|
|
|
JSON_SCAN(json_to_int, &scidd.dir),
|
|
|
|
JSON_SCAN(json_to_msat, &spendable),
|
|
|
|
JSON_SCAN(json_to_msat, &receivable),
|
|
|
|
JSON_SCAN(json_to_bool, &enabled),
|
|
|
|
JSON_SCAN_TAL(tmpctx, json_strdup, &state),
|
|
|
|
JSON_SCAN(json_to_node_id, &dst),
|
|
|
|
JSON_SCAN(json_to_msat, &fee_base[LOCAL]),
|
|
|
|
JSON_SCAN(json_to_u32, &fee_proportional[LOCAL]),
|
|
|
|
JSON_SCAN(json_to_msat, &htlc_min[LOCAL]),
|
|
|
|
JSON_SCAN(json_to_msat, &htlc_max[LOCAL]),
|
|
|
|
JSON_SCAN(json_to_u32, &cltv_delta[LOCAL]),
|
|
|
|
JSON_SCAN(json_to_msat, &fee_base[REMOTE]),
|
|
|
|
JSON_SCAN(json_to_u32, &fee_proportional[REMOTE]),
|
|
|
|
JSON_SCAN(json_to_msat, &htlc_min[REMOTE]),
|
|
|
|
JSON_SCAN(json_to_msat, &htlc_max[REMOTE]),
|
|
|
|
JSON_SCAN(json_to_u32, &cltv_delta[REMOTE]),
|
|
|
|
JSON_SCAN(json_to_short_channel_id, &alias));
|
|
|
|
if (err) {
|
|
|
|
errx(1, "Bad listpeerchannels.channels %zu: %s",
|
|
|
|
i, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use alias if no scid. Note: if alias is set, direction is present */
|
|
|
|
if (scidd.scid.u64 == 0 && alias.u64 != 0)
|
|
|
|
scidd.scid = alias;
|
|
|
|
|
|
|
|
/* Unusable if no scid (yet) */
|
|
|
|
if (scidd.scid.u64 == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Disable if in bad state (it's already false if not connected) */
|
|
|
|
if (!streq(state, "CHANNELD_NORMAL")
|
|
|
|
&& !streq(state, "CHANNELD_AWAITING_SPLICE"))
|
|
|
|
enabled = false;
|
|
|
|
|
pay: ignore fees on our own channels when determining routing.
I noticed that run-route-infloop chose some worse-looking paths after
routing was fixed, eg the second node:
Before:
Destination node, success, probability, hops, fees, cltv, scid...
02b3aa1e4ed31be83cca4bd367b2c01e39502cb25e282a9b4520ad376a1ba0a01a,1,0.991856,2,1004,40,2572260x39x0/1,2131897x45x0/0
After:
Destination node, success, probability, hops, fees, cltv, scid...
02b3aa1e4ed31be83cca4bd367b2c01e39502cb25e282a9b4520ad376a1ba0a01a,1,0.954540,3,1046,46,2570715x21x0/1,2346882x26x14/1,2131897x45x0/0
This is because although the final costs don't reflect it, routing was taking
into account local channels, and 2572260x39x0/1 has a base fee of 2970.
There's an easy fix: when we the pay plugin creates localmods for our
gossip graph, add all local channels with delay and fees equal to 0.
We do the same thing in our unit test. This improves things across
the board:
Linear success probability (when found): min-max(mean +/- stddev)
Before: 0.487040-0.999543(0.952548+/-0.075)
After: 0.486985-0.999750(0.975978+/-0.053)
Hops:
Before: 1-5(2.98374+/-0.77)
After: 1-5(2.09593+/-0.63)
Fees:
Before: 0-50848(922.457+/-2.7e+03)
After: 0-50041(861.621+/-2.7e+03)
Delay (blocks):
Before: 0-196(65.8081+/-60)
After: 0-190(60.3285+/-60)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: Plugins: `pay` route algorithm doesn't bias against our own "expensive" channels any more.
2024-03-07 03:56:58 +01:00
|
|
|
/* We route better if we know we won't charge
|
|
|
|
* ourselves fees (though if fees are a signal on what
|
|
|
|
* channel we prefer to use, this ignores that
|
|
|
|
* signal!) */
|
|
|
|
if (zero_rates) {
|
|
|
|
fee_base[LOCAL] = AMOUNT_MSAT(0);
|
|
|
|
fee_proportional[LOCAL] = 0;
|
|
|
|
cltv_delta[LOCAL] = 0;
|
|
|
|
}
|
|
|
|
|
2023-12-06 21:14:05 +01:00
|
|
|
/* We add both directions */
|
|
|
|
cb(mods, self, &dst, &scidd, htlc_min[LOCAL], htlc_max[LOCAL],
|
2024-03-18 08:31:42 +01:00
|
|
|
spendable, fee_base[LOCAL], fee_proportional[LOCAL],
|
2024-04-02 08:51:05 +02:00
|
|
|
cltv_delta[LOCAL], enabled, buf, channel, cbarg);
|
2023-12-06 21:14:05 +01:00
|
|
|
|
|
|
|
/* If we didn't have a remote update, it's not usable yet */
|
|
|
|
if (fee_proportional[REMOTE] == -1U)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
scidd.dir = !scidd.dir;
|
|
|
|
|
|
|
|
cb(mods, self, &dst, &scidd, htlc_min[REMOTE], htlc_max[REMOTE],
|
2024-03-18 08:31:42 +01:00
|
|
|
receivable, fee_base[REMOTE], fee_proportional[REMOTE],
|
2024-04-02 08:51:05 +02:00
|
|
|
cltv_delta[REMOTE], enabled, buf, channel, cbarg);
|
2023-12-06 21:14:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return mods;
|
|
|
|
}
|
|
|
|
|