mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 06:55:13 +01:00
common: generic routine to turn listpeerchannels into gossmap local updates.
This is more thorough than the minimal one required for getroute(), including the feerates and cltv deltas. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
f2fff4de55
commit
cdaad1bf2a
4 changed files with 238 additions and 83 deletions
|
@ -39,6 +39,7 @@ COMMON_SRC_NOGEN := \
|
||||||
common/fp16.c \
|
common/fp16.c \
|
||||||
common/gossip_store.c \
|
common/gossip_store.c \
|
||||||
common/gossmap.c \
|
common/gossmap.c \
|
||||||
|
common/gossmods_listpeerchannels.c \
|
||||||
common/hash_u5.c \
|
common/hash_u5.c \
|
||||||
common/hmac.c \
|
common/hmac.c \
|
||||||
common/hsm_encryption.c \
|
common/hsm_encryption.c \
|
||||||
|
|
158
common/gossmods_listpeerchannels.c
Normal file
158
common/gossmods_listpeerchannels.c
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
#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,
|
||||||
|
struct amount_msat min,
|
||||||
|
struct amount_msat max,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* FIXME: features? */
|
||||||
|
gossmap_local_addchan(mods, self, peer, &scidd->scid, NULL);
|
||||||
|
|
||||||
|
gossmap_local_updatechan(mods, &scidd->scid, min, max,
|
||||||
|
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,
|
||||||
|
void (*cb)(struct gossmap_localmods *mods,
|
||||||
|
const struct node_id *self,
|
||||||
|
const struct node_id *peer,
|
||||||
|
const struct short_channel_id_dir *scidd,
|
||||||
|
struct amount_msat min,
|
||||||
|
struct amount_msat max,
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Cut htlc max to spendable. */
|
||||||
|
if (amount_msat_less(spendable, htlc_max[LOCAL]))
|
||||||
|
htlc_max[LOCAL] = spendable;
|
||||||
|
|
||||||
|
/* We add both directions */
|
||||||
|
cb(mods, self, &dst, &scidd, htlc_min[LOCAL], htlc_max[LOCAL],
|
||||||
|
fee_base[LOCAL], fee_proportional[LOCAL], cltv_delta[LOCAL],
|
||||||
|
enabled, buf, channel, cbarg);
|
||||||
|
|
||||||
|
/* If we didn't have a remote update, it's not usable yet */
|
||||||
|
if (fee_proportional[REMOTE] == -1U)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
scidd.dir = !scidd.dir;
|
||||||
|
|
||||||
|
/* Cut htlc max to receivable. */
|
||||||
|
if (amount_msat_less(receivable, htlc_max[REMOTE]))
|
||||||
|
htlc_max[REMOTE] = receivable;
|
||||||
|
|
||||||
|
cb(mods, self, &dst, &scidd, htlc_min[REMOTE], htlc_max[REMOTE],
|
||||||
|
fee_base[REMOTE], fee_proportional[REMOTE], cltv_delta[REMOTE],
|
||||||
|
enabled, buf, channel, cbarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
74
common/gossmods_listpeerchannels.h
Normal file
74
common/gossmods_listpeerchannels.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef LIGHTNING_COMMON_GOSSMODS_LISTPEERCHANNELS_H
|
||||||
|
#define LIGHTNING_COMMON_GOSSMODS_LISTPEERCHANNELS_H
|
||||||
|
#include "config.h"
|
||||||
|
#include <bitcoin/short_channel_id.h>
|
||||||
|
#include <ccan/typesafe_cb/typesafe_cb.h>
|
||||||
|
#include <common/amount.h>
|
||||||
|
#include <common/json_parse_simple.h>
|
||||||
|
|
||||||
|
struct node_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gossmods_from_listpeerchannels: create gossmap_localmods from `listpeerchannels`
|
||||||
|
* @ctx: context to allocate return from
|
||||||
|
* @buf: the JSON buffer from listpeerchannels
|
||||||
|
* @toks: the JSON tokens
|
||||||
|
* @cb: optional per-channel callback.
|
||||||
|
* @cbarg: arg for @cb.
|
||||||
|
*
|
||||||
|
* This constructs a set of modifications you can apply to your gossmap to include
|
||||||
|
* local (esp. private) channels. You can also have an optional per-channel callback
|
||||||
|
* for special effects.
|
||||||
|
*/
|
||||||
|
struct gossmap_localmods *gossmods_from_listpeerchannels_(const tal_t *ctx,
|
||||||
|
const struct node_id *self,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *toks,
|
||||||
|
void (*cb)(struct gossmap_localmods *mods,
|
||||||
|
const struct node_id *self_,
|
||||||
|
const struct node_id *peer,
|
||||||
|
const struct short_channel_id_dir *scidd,
|
||||||
|
struct amount_msat min,
|
||||||
|
struct amount_msat max,
|
||||||
|
struct amount_msat fee_base,
|
||||||
|
u32 fee_proportional,
|
||||||
|
u32 cltv_delta,
|
||||||
|
bool enabled,
|
||||||
|
const char *buf_,
|
||||||
|
const jsmntok_t *chantok,
|
||||||
|
void *cbarg_),
|
||||||
|
void *cbarg);
|
||||||
|
|
||||||
|
#define gossmods_from_listpeerchannels(ctx, self, buf, toks, cb, cbarg) \
|
||||||
|
gossmods_from_listpeerchannels_((ctx), (self), (buf), (toks), \
|
||||||
|
typesafe_cb_preargs(void, void *, (cb), (cbarg), \
|
||||||
|
struct gossmap_localmods *, \
|
||||||
|
const struct node_id *, \
|
||||||
|
const struct node_id *, \
|
||||||
|
const struct short_channel_id_dir *, \
|
||||||
|
struct amount_msat, \
|
||||||
|
struct amount_msat, \
|
||||||
|
struct amount_msat, \
|
||||||
|
u32, \
|
||||||
|
u32, \
|
||||||
|
bool, \
|
||||||
|
const char *, \
|
||||||
|
const jsmntok_t *), \
|
||||||
|
(cbarg))
|
||||||
|
|
||||||
|
/* Callback which simply adds to gossmap. */
|
||||||
|
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,
|
||||||
|
struct amount_msat min,
|
||||||
|
struct amount_msat max,
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif /* LIGHTNING_COMMON_GOSSMODS_LISTPEERCHANNELS_H */
|
|
@ -6,6 +6,7 @@
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <common/dijkstra.h>
|
#include <common/dijkstra.h>
|
||||||
#include <common/gossmap.h>
|
#include <common/gossmap.h>
|
||||||
|
#include <common/gossmods_listpeerchannels.h>
|
||||||
#include <common/json_param.h>
|
#include <common/json_param.h>
|
||||||
#include <common/json_stream.h>
|
#include <common/json_stream.h>
|
||||||
#include <common/memleak.h>
|
#include <common/memleak.h>
|
||||||
|
@ -148,86 +149,6 @@ static struct command_result *try_route(struct command *cmd,
|
||||||
return command_finished(cmd, js);
|
return command_finished(cmd, js);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct gossmap_localmods *
|
|
||||||
gossmods_from_listpeerchannels(const tal_t *ctx,
|
|
||||||
struct plugin *plugin,
|
|
||||||
struct gossmap *gossmap,
|
|
||||||
const char *buf,
|
|
||||||
const jsmntok_t *toks)
|
|
||||||
{
|
|
||||||
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 scid;
|
|
||||||
int dir;
|
|
||||||
bool connected;
|
|
||||||
struct node_id dst;
|
|
||||||
struct amount_msat capacity;
|
|
||||||
const char *state, *err;
|
|
||||||
|
|
||||||
/* scid/direction may not exist. */
|
|
||||||
scid.u64 = 0;
|
|
||||||
capacity = AMOUNT_MSAT(0);
|
|
||||||
err = json_scan(tmpctx, buf, channel,
|
|
||||||
"{short_channel_id?:%,"
|
|
||||||
"direction?:%,"
|
|
||||||
"spendable_msat?:%,"
|
|
||||||
"peer_connected:%,"
|
|
||||||
"state:%,"
|
|
||||||
"peer_id:%}",
|
|
||||||
JSON_SCAN(json_to_short_channel_id, &scid),
|
|
||||||
JSON_SCAN(json_to_int, &dir),
|
|
||||||
JSON_SCAN(json_to_msat, &capacity),
|
|
||||||
JSON_SCAN(json_to_bool, &connected),
|
|
||||||
JSON_SCAN_TAL(tmpctx, json_strdup, &state),
|
|
||||||
JSON_SCAN(json_to_node_id, &dst));
|
|
||||||
if (err) {
|
|
||||||
plugin_err(plugin,
|
|
||||||
"Bad listpeerchannels.channels %zu: %s",
|
|
||||||
i, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unusable if no scid (yet) */
|
|
||||||
if (scid.u64 == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Disable if in bad state, or disconnected */
|
|
||||||
if (!streq(state, "CHANNELD_NORMAL")
|
|
||||||
&& !streq(state, "CHANNELD_AWAITING_SPLICE")) {
|
|
||||||
goto disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!connected) {
|
|
||||||
goto disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: features? */
|
|
||||||
gossmap_local_addchan(mods, &local_id, &dst, &scid, NULL);
|
|
||||||
gossmap_local_updatechan(mods, &scid,
|
|
||||||
AMOUNT_MSAT(0), capacity,
|
|
||||||
/* We don't charge ourselves fees */
|
|
||||||
0, 0, 0,
|
|
||||||
true,
|
|
||||||
dir);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
disable:
|
|
||||||
/* Only apply fake "disabled" if channel exists */
|
|
||||||
if (gossmap_find_chan(gossmap, &scid)) {
|
|
||||||
gossmap_local_updatechan(mods, &scid,
|
|
||||||
AMOUNT_MSAT(0), AMOUNT_MSAT(0),
|
|
||||||
0, 0, 0,
|
|
||||||
false,
|
|
||||||
dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct command_result *
|
static struct command_result *
|
||||||
listpeerchannels_getroute_done(struct command *cmd,
|
listpeerchannels_getroute_done(struct command *cmd,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
|
@ -239,11 +160,12 @@ listpeerchannels_getroute_done(struct command *cmd,
|
||||||
struct command_result *res;
|
struct command_result *res;
|
||||||
|
|
||||||
/* Get local knowledge */
|
/* Get local knowledge */
|
||||||
gossmap = get_gossmap();
|
mods = gossmods_from_listpeerchannels(tmpctx, &local_id,
|
||||||
mods = gossmods_from_listpeerchannels(tmpctx, cmd->plugin,
|
buf, result,
|
||||||
gossmap, buf, result);
|
gossmod_add_localchan, NULL);
|
||||||
|
|
||||||
/* Overlay local knowledge for dijkstra */
|
/* Overlay local knowledge for dijkstra */
|
||||||
|
gossmap = get_gossmap();
|
||||||
gossmap_apply_localmods(gossmap, mods);
|
gossmap_apply_localmods(gossmap, mods);
|
||||||
res = try_route(cmd, gossmap, info);
|
res = try_route(cmd, gossmap, info);
|
||||||
gossmap_remove_localmods(gossmap, mods);
|
gossmap_remove_localmods(gossmap, mods);
|
||||||
|
|
Loading…
Add table
Reference in a new issue