mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
gossipd: hand all candidates up to lightningd to select routeboost.
This lets us do more flexible filtering in the next patch. But it also keeps some weird logic out of gossipd. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
3f3a48dae9
commit
11dc1b341c
5 changed files with 135 additions and 57 deletions
|
@ -128,12 +128,15 @@ msgdata,gossip_dev_compact_store_reply,success,bool,
|
||||||
|
|
||||||
# master -> gossipd: get route_info for our incoming channels
|
# master -> gossipd: get route_info for our incoming channels
|
||||||
msgtype,gossip_get_incoming_channels,3025
|
msgtype,gossip_get_incoming_channels,3025
|
||||||
msgdata,gossip_get_incoming_channels,private_too,?bool,
|
|
||||||
|
|
||||||
# gossipd -> master: here they are.
|
# gossipd -> master: here they are.
|
||||||
msgtype,gossip_get_incoming_channels_reply,3125
|
msgtype,gossip_get_incoming_channels_reply,3125
|
||||||
msgdata,gossip_get_incoming_channels_reply,num,u16,
|
msgdata,gossip_get_incoming_channels_reply,num_public,u16,
|
||||||
msgdata,gossip_get_incoming_channels_reply,route_info,route_info,num
|
msgdata,gossip_get_incoming_channels_reply,public_route_info,route_info,num_public
|
||||||
|
msgdata,gossip_get_incoming_channels_reply,public_deadends,bool,num_public
|
||||||
|
msgdata,gossip_get_incoming_channels_reply,num_private,u16,
|
||||||
|
msgdata,gossip_get_incoming_channels_reply,private_route_info,route_info,num_private
|
||||||
|
msgdata,gossip_get_incoming_channels_reply,private_deadends,bool,num_private
|
||||||
|
|
||||||
# master -> gossipd: blockheight increased.
|
# master -> gossipd: blockheight increased.
|
||||||
msgtype,gossip_new_blockheight,3026
|
msgtype,gossip_new_blockheight,3026
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 6.
|
|
@ -1188,18 +1188,6 @@ static bool node_has_public_channels(const struct node *peer,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*~ The `exposeprivate` flag is a trinary: NULL == dynamic, otherwise
|
|
||||||
* value decides. Thus, we provide two wrappers for clarity: */
|
|
||||||
static bool never_expose(bool *exposeprivate)
|
|
||||||
{
|
|
||||||
return exposeprivate && !*exposeprivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool always_expose(bool *exposeprivate)
|
|
||||||
{
|
|
||||||
return exposeprivate && *exposeprivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*~ For routeboost, we offer payers a hint of what incoming channels might
|
/*~ For routeboost, we offer payers a hint of what incoming channels might
|
||||||
* have capacity for their payment. To do this, lightningd asks for the
|
* have capacity for their payment. To do this, lightningd asks for the
|
||||||
* information about all channels to this node; but gossipd doesn't know about
|
* information about all channels to this node; but gossipd doesn't know about
|
||||||
|
@ -1211,14 +1199,12 @@ static struct io_plan *get_incoming_channels(struct io_conn *conn,
|
||||||
struct node *node;
|
struct node *node;
|
||||||
struct route_info *public = tal_arr(tmpctx, struct route_info, 0);
|
struct route_info *public = tal_arr(tmpctx, struct route_info, 0);
|
||||||
struct route_info *private = tal_arr(tmpctx, struct route_info, 0);
|
struct route_info *private = tal_arr(tmpctx, struct route_info, 0);
|
||||||
bool has_public;
|
bool *priv_deadends = tal_arr(tmpctx, bool, 0);
|
||||||
bool *exposeprivate;
|
bool *pub_deadends = tal_arr(tmpctx, bool, 0);
|
||||||
|
|
||||||
if (!fromwire_gossip_get_incoming_channels(tmpctx, msg, &exposeprivate))
|
if (!fromwire_gossip_get_incoming_channels(msg))
|
||||||
master_badmsg(WIRE_GOSSIP_GET_INCOMING_CHANNELS, msg);
|
master_badmsg(WIRE_GOSSIP_GET_INCOMING_CHANNELS, msg);
|
||||||
|
|
||||||
has_public = always_expose(exposeprivate);
|
|
||||||
|
|
||||||
node = get_node(daemon->rstate, &daemon->rstate->local_id);
|
node = get_node(daemon->rstate, &daemon->rstate->local_id);
|
||||||
if (node) {
|
if (node) {
|
||||||
struct chan_map_iter i;
|
struct chan_map_iter i;
|
||||||
|
@ -1227,6 +1213,7 @@ static struct io_plan *get_incoming_channels(struct io_conn *conn,
|
||||||
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
||||||
const struct half_chan *hc;
|
const struct half_chan *hc;
|
||||||
struct route_info ri;
|
struct route_info ri;
|
||||||
|
bool deadend;
|
||||||
|
|
||||||
hc = &c->half[half_chan_to(node, c)];
|
hc = &c->half[half_chan_to(node, c)];
|
||||||
|
|
||||||
|
@ -1239,25 +1226,21 @@ static struct io_plan *get_incoming_channels(struct io_conn *conn,
|
||||||
ri.fee_proportional_millionths = hc->proportional_fee;
|
ri.fee_proportional_millionths = hc->proportional_fee;
|
||||||
ri.cltv_expiry_delta = hc->delay;
|
ri.cltv_expiry_delta = hc->delay;
|
||||||
|
|
||||||
has_public |= is_chan_public(c);
|
deadend = !node_has_public_channels(other_node(node, c),
|
||||||
|
c);
|
||||||
/* If peer doesn't have other public channels,
|
if (is_chan_public(c)) {
|
||||||
* no point giving route */
|
|
||||||
if (!node_has_public_channels(other_node(node, c), c))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (always_expose(exposeprivate) || is_chan_public(c))
|
|
||||||
tal_arr_expand(&public, ri);
|
tal_arr_expand(&public, ri);
|
||||||
else
|
tal_arr_expand(&pub_deadends, deadend);
|
||||||
|
} else {
|
||||||
tal_arr_expand(&private, ri);
|
tal_arr_expand(&private, ri);
|
||||||
|
tal_arr_expand(&priv_deadends, deadend);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no public channels (even deadend ones!), share private ones. */
|
msg = towire_gossip_get_incoming_channels_reply(NULL,
|
||||||
if (!has_public && !never_expose(exposeprivate))
|
public, pub_deadends,
|
||||||
msg = towire_gossip_get_incoming_channels_reply(NULL, private);
|
private, priv_deadends);
|
||||||
else
|
|
||||||
msg = towire_gossip_get_incoming_channels_reply(NULL, public);
|
|
||||||
daemon_conn_send(daemon->master, take(msg));
|
daemon_conn_send(daemon->master, take(msg));
|
||||||
|
|
||||||
return daemon_conn_read_next(conn, daemon->master);
|
return daemon_conn_read_next(conn, daemon->master);
|
||||||
|
|
|
@ -379,6 +379,7 @@ static struct route_info **select_inchan(const tal_t *ctx,
|
||||||
struct lightningd *ld,
|
struct lightningd *ld,
|
||||||
struct amount_msat amount_needed,
|
struct amount_msat amount_needed,
|
||||||
const struct route_info *inchans,
|
const struct route_info *inchans,
|
||||||
|
const bool *deadends,
|
||||||
bool *any_offline)
|
bool *any_offline)
|
||||||
{
|
{
|
||||||
/* BOLT11 struct wants an array of arrays (can provide multiple routes) */
|
/* BOLT11 struct wants an array of arrays (can provide multiple routes) */
|
||||||
|
@ -413,6 +414,10 @@ static struct route_info **select_inchan(const tal_t *ctx,
|
||||||
if (!c)
|
if (!c)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Is it a dead-end? */
|
||||||
|
if (deadends[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Channel balance as seen by our node:
|
/* Channel balance as seen by our node:
|
||||||
|
|
||||||
|<----------------- capacity ----------------->|
|
|<----------------- capacity ----------------->|
|
||||||
|
@ -494,30 +499,88 @@ static struct route_info **select_inchan(const tal_t *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encapsulating struct while we wait for gossipd to give us incoming channels */
|
/* Encapsulating struct while we wait for gossipd to give us incoming channels */
|
||||||
|
struct chanhints {
|
||||||
|
bool expose_all_private;
|
||||||
|
struct short_channel_id *hints;
|
||||||
|
};
|
||||||
|
|
||||||
struct invoice_info {
|
struct invoice_info {
|
||||||
struct command *cmd;
|
struct command *cmd;
|
||||||
struct preimage payment_preimage;
|
struct preimage payment_preimage;
|
||||||
struct bolt11 *b11;
|
struct bolt11 *b11;
|
||||||
struct json_escape *label;
|
struct json_escape *label;
|
||||||
|
struct chanhints *chanhints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void append_routes(struct route_info **dst, const struct route_info *src)
|
||||||
|
{
|
||||||
|
size_t n = tal_count(*dst);
|
||||||
|
|
||||||
|
tal_resize(dst, n + tal_count(src));
|
||||||
|
memcpy(*dst + n, src, tal_count(src) * sizeof(*src));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_bools(bool **dst, const bool *src)
|
||||||
|
{
|
||||||
|
size_t n = tal_count(*dst);
|
||||||
|
|
||||||
|
tal_resize(dst, n + tal_count(src));
|
||||||
|
memcpy(*dst + n, src, tal_count(src) * sizeof(*src));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool all_true(const bool *barr, size_t n)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
if (!barr[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void gossipd_incoming_channels_reply(struct subd *gossipd,
|
static void gossipd_incoming_channels_reply(struct subd *gossipd,
|
||||||
const u8 *msg,
|
const u8 *msg,
|
||||||
const int *fs,
|
const int *fs,
|
||||||
struct invoice_info *info)
|
struct invoice_info *info)
|
||||||
{
|
{
|
||||||
struct json_stream *response;
|
struct json_stream *response;
|
||||||
struct route_info *inchans;
|
struct route_info *inchans, *private;
|
||||||
|
bool *inchan_deadends, *private_deadends;
|
||||||
bool any_offline;
|
bool any_offline;
|
||||||
struct invoice invoice;
|
struct invoice invoice;
|
||||||
char *b11enc;
|
char *b11enc;
|
||||||
const struct invoice_details *details;
|
const struct invoice_details *details;
|
||||||
struct wallet *wallet = info->cmd->ld->wallet;
|
struct wallet *wallet = info->cmd->ld->wallet;
|
||||||
|
const struct chanhints *chanhints = info->chanhints;
|
||||||
|
|
||||||
if (!fromwire_gossip_get_incoming_channels_reply(tmpctx, msg, &inchans))
|
if (!fromwire_gossip_get_incoming_channels_reply(tmpctx, msg,
|
||||||
|
&inchans,
|
||||||
|
&inchan_deadends,
|
||||||
|
&private,
|
||||||
|
&private_deadends))
|
||||||
fatal("Gossip gave bad GOSSIP_GET_INCOMING_CHANNELS_REPLY %s",
|
fatal("Gossip gave bad GOSSIP_GET_INCOMING_CHANNELS_REPLY %s",
|
||||||
tal_hex(msg, msg));
|
tal_hex(msg, msg));
|
||||||
|
|
||||||
|
/* fromwire explicitly makes empty arrays into NULL */
|
||||||
|
if (!inchans) {
|
||||||
|
inchans = tal_arr(tmpctx, struct route_info, 0);
|
||||||
|
inchan_deadends = tal_arr(tmpctx, bool, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chanhints->expose_all_private) {
|
||||||
|
append_routes(&inchans, private);
|
||||||
|
append_bools(&inchan_deadends, private_deadends);
|
||||||
|
} else if (chanhints->hints) {
|
||||||
|
/* FIXME: Implement hint support! */
|
||||||
|
assert(!tal_count(chanhints->hints));
|
||||||
|
} else {
|
||||||
|
/* By default, only consider private channels if there are
|
||||||
|
* no public channels *at all* */
|
||||||
|
if (tal_count(inchans) == 0) {
|
||||||
|
append_routes(&inchans, private);
|
||||||
|
append_bools(&inchan_deadends, private_deadends);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
/* dev-routes overrides this. */
|
/* dev-routes overrides this. */
|
||||||
any_offline = false;
|
any_offline = false;
|
||||||
|
@ -528,6 +591,7 @@ static void gossipd_incoming_channels_reply(struct subd *gossipd,
|
||||||
info->cmd->ld,
|
info->cmd->ld,
|
||||||
info->b11->msat ? *info->b11->msat : AMOUNT_MSAT(1),
|
info->b11->msat ? *info->b11->msat : AMOUNT_MSAT(1),
|
||||||
inchans,
|
inchans,
|
||||||
|
inchan_deadends,
|
||||||
&any_offline);
|
&any_offline);
|
||||||
|
|
||||||
/* FIXME: add private routes if necessary! */
|
/* FIXME: add private routes if necessary! */
|
||||||
|
@ -578,14 +642,19 @@ static void gossipd_incoming_channels_reply(struct subd *gossipd,
|
||||||
any_offline
|
any_offline
|
||||||
? " (among currently connected peers)" : "");
|
? " (among currently connected peers)" : "");
|
||||||
|
|
||||||
if (any_offline)
|
if (tal_count(inchans) == 0)
|
||||||
|
json_add_string(response, "warning_capacity",
|
||||||
|
"No channels");
|
||||||
|
else if (all_true(inchan_deadends, tal_count(inchans)))
|
||||||
|
json_add_string(response, "warning_deadends",
|
||||||
|
"No channel with a peer that is not a dead end");
|
||||||
|
else if (any_offline)
|
||||||
json_add_string(response, "warning_offline",
|
json_add_string(response, "warning_offline",
|
||||||
"No channel with a peer that is currently connected"
|
"No channel with a peer that is currently connected"
|
||||||
" has sufficient incoming capacity");
|
" has sufficient incoming capacity");
|
||||||
else
|
else
|
||||||
json_add_string(response, "warning_capacity",
|
json_add_string(response, "warning_capacity",
|
||||||
"No channel with a peer that is not a dead end,"
|
"No channel with a peer that has sufficient incoming capacity");
|
||||||
" has sufficient incoming capacity");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
was_pending(command_success(info->cmd, response));
|
was_pending(command_success(info->cmd, response));
|
||||||
|
@ -739,6 +808,7 @@ static struct command_result *json_invoice(struct command *cmd,
|
||||||
|
|
||||||
info = tal(cmd, struct invoice_info);
|
info = tal(cmd, struct invoice_info);
|
||||||
info->cmd = cmd;
|
info->cmd = cmd;
|
||||||
|
info->chanhints = tal(info, struct chanhints);
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_req("msatoshi", param_msat_or_any, &msatoshi_val),
|
p_req("msatoshi", param_msat_or_any, &msatoshi_val),
|
||||||
|
@ -769,6 +839,17 @@ static struct command_result *json_invoice(struct command *cmd,
|
||||||
strlen(desc_val));
|
strlen(desc_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default is expose iff no public channels. */
|
||||||
|
if (exposeprivate == NULL) {
|
||||||
|
info->chanhints->expose_all_private = false;
|
||||||
|
info->chanhints->hints = NULL;
|
||||||
|
} else {
|
||||||
|
info->chanhints->expose_all_private = *exposeprivate;
|
||||||
|
/* FIXME: Support hints! */
|
||||||
|
info->chanhints->hints = tal_arr(info->chanhints,
|
||||||
|
struct short_channel_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (msatoshi_val
|
if (msatoshi_val
|
||||||
&& amount_msat_greater(*msatoshi_val, chainparams->max_payment)) {
|
&& amount_msat_greater(*msatoshi_val, chainparams->max_payment)) {
|
||||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
|
@ -829,10 +910,8 @@ static struct command_result *json_invoice(struct command *cmd,
|
||||||
if (fallback_scripts)
|
if (fallback_scripts)
|
||||||
info->b11->fallbacks = tal_steal(info->b11, fallback_scripts);
|
info->b11->fallbacks = tal_steal(info->b11, fallback_scripts);
|
||||||
|
|
||||||
log_debug(cmd->ld->log, "exposeprivate = %s",
|
|
||||||
exposeprivate ? (*exposeprivate ? "TRUE" : "FALSE") : "NULL");
|
|
||||||
subd_req(cmd, cmd->ld->gossip,
|
subd_req(cmd, cmd->ld->gossip,
|
||||||
take(towire_gossip_get_incoming_channels(NULL, exposeprivate)),
|
take(towire_gossip_get_incoming_channels(NULL)),
|
||||||
-1, 0, gossipd_incoming_channels_reply, info);
|
-1, 0, gossipd_incoming_channels_reply, info);
|
||||||
|
|
||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
|
|
|
@ -107,7 +107,7 @@ bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEE
|
||||||
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **features UNNEEDED)
|
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **features UNNEEDED)
|
||||||
{ fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
|
{ fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
|
||||||
/* Generated stub for fromwire_gossip_get_incoming_channels_reply */
|
/* Generated stub for fromwire_gossip_get_incoming_channels_reply */
|
||||||
bool fromwire_gossip_get_incoming_channels_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct route_info **route_info UNNEEDED)
|
bool fromwire_gossip_get_incoming_channels_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct route_info **public_route_info UNNEEDED, bool **public_deadends UNNEEDED, struct route_info **private_route_info UNNEEDED, bool **private_deadends UNNEEDED)
|
||||||
{ fprintf(stderr, "fromwire_gossip_get_incoming_channels_reply called!\n"); abort(); }
|
{ fprintf(stderr, "fromwire_gossip_get_incoming_channels_reply called!\n"); abort(); }
|
||||||
/* Generated stub for fromwire_hsm_get_channel_basepoints_reply */
|
/* Generated stub for fromwire_hsm_get_channel_basepoints_reply */
|
||||||
bool fromwire_hsm_get_channel_basepoints_reply(const void *p UNNEEDED, struct basepoints *basepoints UNNEEDED, struct pubkey *funding_pubkey UNNEEDED)
|
bool fromwire_hsm_get_channel_basepoints_reply(const void *p UNNEEDED, struct basepoints *basepoints UNNEEDED, struct pubkey *funding_pubkey UNNEEDED)
|
||||||
|
@ -473,7 +473,7 @@ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
|
||||||
const char *fmt UNNEEDED, ...)
|
const char *fmt UNNEEDED, ...)
|
||||||
{ fprintf(stderr, "towire_errorfmt called!\n"); abort(); }
|
{ fprintf(stderr, "towire_errorfmt called!\n"); abort(); }
|
||||||
/* Generated stub for towire_gossip_get_incoming_channels */
|
/* Generated stub for towire_gossip_get_incoming_channels */
|
||||||
u8 *towire_gossip_get_incoming_channels(const tal_t *ctx UNNEEDED, bool *private_too UNNEEDED)
|
u8 *towire_gossip_get_incoming_channels(const tal_t *ctx UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_gossip_get_incoming_channels called!\n"); abort(); }
|
{ fprintf(stderr, "towire_gossip_get_incoming_channels called!\n"); abort(); }
|
||||||
/* Generated stub for towire_hsm_get_channel_basepoints */
|
/* Generated stub for towire_hsm_get_channel_basepoints */
|
||||||
u8 *towire_hsm_get_channel_basepoints(const tal_t *ctx UNNEEDED, const struct node_id *peerid UNNEEDED, u64 dbid UNNEEDED)
|
u8 *towire_hsm_get_channel_basepoints(const tal_t *ctx UNNEEDED, const struct node_id *peerid UNNEEDED, u64 dbid UNNEEDED)
|
||||||
|
@ -686,6 +686,7 @@ int main(void)
|
||||||
struct lightningd *ld;
|
struct lightningd *ld;
|
||||||
bool any_offline;
|
bool any_offline;
|
||||||
struct route_info *inchans;
|
struct route_info *inchans;
|
||||||
|
bool *deadends;
|
||||||
struct route_info **ret;
|
struct route_info **ret;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
|
@ -698,51 +699,53 @@ int main(void)
|
||||||
list_head_init(&ld->peers);
|
list_head_init(&ld->peers);
|
||||||
|
|
||||||
inchans = tal_arr(tmpctx, struct route_info, 0);
|
inchans = tal_arr(tmpctx, struct route_info, 0);
|
||||||
|
deadends = tal_arrz(tmpctx, bool, 100);
|
||||||
|
|
||||||
/* 1. Nothing to choose from -> NULL result. */
|
/* 1. Nothing to choose from -> NULL result. */
|
||||||
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, &any_offline) == NULL);
|
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL);
|
||||||
assert(any_offline == false);
|
assert(any_offline == false);
|
||||||
|
|
||||||
/* 2. inchan but no corresponding peer -> NULL result. */
|
/* 2. inchan but no corresponding peer -> NULL result. */
|
||||||
add_inchan(&inchans, 0);
|
add_inchan(&inchans, 0);
|
||||||
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, &any_offline) == NULL);
|
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL);
|
||||||
assert(any_offline == false);
|
assert(any_offline == false);
|
||||||
|
|
||||||
/* 3. inchan but its peer in awaiting lockin -> NULL result. */
|
/* 3. inchan but its peer in awaiting lockin -> NULL result. */
|
||||||
add_peer(ld, 0, CHANNELD_AWAITING_LOCKIN, true);
|
add_peer(ld, 0, CHANNELD_AWAITING_LOCKIN, true);
|
||||||
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, &any_offline) == NULL);
|
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL);
|
||||||
assert(any_offline == false);
|
assert(any_offline == false);
|
||||||
|
|
||||||
/* 4. connected peer but no corresponding inchan -> NULL result. */
|
/* 4. connected peer but no corresponding inchan -> NULL result. */
|
||||||
add_peer(ld, 1, CHANNELD_NORMAL, true);
|
add_peer(ld, 1, CHANNELD_NORMAL, true);
|
||||||
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, &any_offline) == NULL);
|
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL);
|
||||||
assert(any_offline == false);
|
assert(any_offline == false);
|
||||||
|
|
||||||
/* 5. inchan but its peer (replaced with one) offline -> NULL result. */
|
/* 5. inchan but its peer (replaced with one) offline -> NULL result. */
|
||||||
list_del_from(&ld->peers, &list_tail(&ld->peers, struct peer, list)->list);
|
list_del_from(&ld->peers, &list_tail(&ld->peers, struct peer, list)->list);
|
||||||
add_peer(ld, 1, CHANNELD_NORMAL, false);
|
add_peer(ld, 1, CHANNELD_NORMAL, false);
|
||||||
add_inchan(&inchans, 1);
|
add_inchan(&inchans, 1);
|
||||||
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, &any_offline) == NULL);
|
assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL);
|
||||||
assert(any_offline == true);
|
assert(any_offline == true);
|
||||||
|
|
||||||
/* 6. Finally, a correct peer! */
|
/* 6. Finally, a correct peer! */
|
||||||
add_inchan(&inchans, 2);
|
add_inchan(&inchans, 2);
|
||||||
add_peer(ld, 2, CHANNELD_NORMAL, true);
|
add_peer(ld, 2, CHANNELD_NORMAL, true);
|
||||||
|
|
||||||
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, &any_offline);
|
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline);
|
||||||
assert(tal_count(ret) == 1);
|
assert(tal_count(ret) == 1);
|
||||||
assert(tal_count(ret[0]) == 1);
|
assert(tal_count(ret[0]) == 1);
|
||||||
assert(any_offline == true); /* Peer 1 is offline */
|
assert(any_offline == true); /* Peer 1 is offline */
|
||||||
assert(route_info_eq(ret[0], &inchans[2]));
|
assert(route_info_eq(ret[0], &inchans[2]));
|
||||||
|
|
||||||
/* 7. Correct peer with just enough capacity_to_pay_us */
|
/* 7. Correct peer with just enough capacity_to_pay_us */
|
||||||
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1999), inchans, &any_offline);
|
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1999), inchans, deadends, &any_offline);
|
||||||
assert(tal_count(ret) == 1);
|
assert(tal_count(ret) == 1);
|
||||||
assert(tal_count(ret[0]) == 1);
|
assert(tal_count(ret[0]) == 1);
|
||||||
assert(any_offline == false); /* Other candidate insufficient funds. */
|
assert(any_offline == false); /* Other candidate insufficient funds. */
|
||||||
assert(route_info_eq(ret[0], &inchans[2]));
|
assert(route_info_eq(ret[0], &inchans[2]));
|
||||||
|
|
||||||
/* 8. Not if we ask for too much! Our balance is 1msat. */
|
/* 8. Not if we ask for too much! Our balance is 1msat. */
|
||||||
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(2000), inchans, &any_offline);
|
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(2000), inchans, deadends, &any_offline);
|
||||||
assert(ret == NULL);
|
assert(ret == NULL);
|
||||||
assert(any_offline == false); /* Other candidate insufficient funds. */
|
assert(any_offline == false); /* Other candidate insufficient funds. */
|
||||||
|
|
||||||
|
@ -752,7 +755,7 @@ int main(void)
|
||||||
|
|
||||||
/* Simulate selection ratios between excesses 25% and 50% of capacity*/
|
/* Simulate selection ratios between excesses 25% and 50% of capacity*/
|
||||||
for (size_t i = n = 0; i < 1000; i++) {
|
for (size_t i = n = 0; i < 1000; i++) {
|
||||||
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1499), inchans, &any_offline);
|
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1499), inchans, deadends, &any_offline);
|
||||||
assert(tal_count(ret) == 1);
|
assert(tal_count(ret) == 1);
|
||||||
assert(tal_count(ret[0]) == 1);
|
assert(tal_count(ret[0]) == 1);
|
||||||
assert(any_offline == false); /* Other candidate insufficient funds. */
|
assert(any_offline == false); /* Other candidate insufficient funds. */
|
||||||
|
@ -770,11 +773,11 @@ int main(void)
|
||||||
/* 10. Last peer's capacity goes from 3 to 2 sat*/
|
/* 10. Last peer's capacity goes from 3 to 2 sat*/
|
||||||
list_tail(&list_tail(&ld->peers, struct peer, list)->channels, struct channel, list)->
|
list_tail(&list_tail(&ld->peers, struct peer, list)->channels, struct channel, list)->
|
||||||
channel_info.their_config.channel_reserve = AMOUNT_SAT(1);
|
channel_info.their_config.channel_reserve = AMOUNT_SAT(1);
|
||||||
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1499), inchans, &any_offline);
|
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1499), inchans, deadends, &any_offline);
|
||||||
|
|
||||||
/* Simulate selection ratios between excesses 25% and 75% of capacity*/
|
/* Simulate selection ratios between excesses 25% and 75% of capacity*/
|
||||||
for (size_t i = n = 0; i < 1000; i++) {
|
for (size_t i = n = 0; i < 1000; i++) {
|
||||||
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1499), inchans, &any_offline);
|
ret = select_inchan(tmpctx, ld, AMOUNT_MSAT(1499), inchans, deadends, &any_offline);
|
||||||
assert(tal_count(ret) == 1);
|
assert(tal_count(ret) == 1);
|
||||||
assert(tal_count(ret[0]) == 1);
|
assert(tal_count(ret[0]) == 1);
|
||||||
assert(any_offline == false); /* Other candidate insufficient funds. */
|
assert(any_offline == false); /* Other candidate insufficient funds. */
|
||||||
|
|
|
@ -136,6 +136,7 @@ def test_invoice_routeboost(node_factory, bitcoind):
|
||||||
# Check routeboost.
|
# Check routeboost.
|
||||||
assert 'warning_capacity' not in inv
|
assert 'warning_capacity' not in inv
|
||||||
assert 'warning_offline' not in inv
|
assert 'warning_offline' not in inv
|
||||||
|
assert 'warning_deadends' not in inv
|
||||||
# Route array has single route with single element.
|
# Route array has single route with single element.
|
||||||
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
|
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
|
||||||
assert r['pubkey'] == l1.info['id']
|
assert r['pubkey'] == l1.info['id']
|
||||||
|
@ -153,6 +154,7 @@ def test_invoice_routeboost(node_factory, bitcoind):
|
||||||
# Check warning
|
# Check warning
|
||||||
assert 'warning_capacity' in inv
|
assert 'warning_capacity' in inv
|
||||||
assert 'warning_offline' not in inv
|
assert 'warning_offline' not in inv
|
||||||
|
assert 'warning_deadends' not in inv
|
||||||
|
|
||||||
l1.rpc.disconnect(l2.info['id'], True)
|
l1.rpc.disconnect(l2.info['id'], True)
|
||||||
wait_for(lambda: not only_one(l2.rpc.listpeers(l1.info['id'])['peers'])['connected'])
|
wait_for(lambda: not only_one(l2.rpc.listpeers(l1.info['id'])['peers'])['connected'])
|
||||||
|
@ -160,6 +162,7 @@ def test_invoice_routeboost(node_factory, bitcoind):
|
||||||
inv = l2.rpc.invoice(123456, label="inv3", description="?")
|
inv = l2.rpc.invoice(123456, label="inv3", description="?")
|
||||||
# Check warning.
|
# Check warning.
|
||||||
assert 'warning_capacity' not in inv
|
assert 'warning_capacity' not in inv
|
||||||
|
assert 'warning_deadends' not in inv
|
||||||
assert 'warning_offline' in inv
|
assert 'warning_offline' in inv
|
||||||
|
|
||||||
# Close l0, l2 will not use l1 at all.
|
# Close l0, l2 will not use l1 at all.
|
||||||
|
@ -171,7 +174,8 @@ def test_invoice_routeboost(node_factory, bitcoind):
|
||||||
wait_for(lambda: len(l2.rpc.listchannels()['channels']) == 2)
|
wait_for(lambda: len(l2.rpc.listchannels()['channels']) == 2)
|
||||||
inv = l2.rpc.invoice(123456, label="inv4", description="?")
|
inv = l2.rpc.invoice(123456, label="inv4", description="?")
|
||||||
# Check warning.
|
# Check warning.
|
||||||
assert 'warning_capacity' in inv
|
assert 'warning_deadends' in inv
|
||||||
|
assert 'warning_capacity' not in inv
|
||||||
assert 'warning_offline' not in inv
|
assert 'warning_offline' not in inv
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,6 +199,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
|
||||||
inv = l2.rpc.invoice(msatoshi=123456, label="inv0", description="?")
|
inv = l2.rpc.invoice(msatoshi=123456, label="inv0", description="?")
|
||||||
assert 'warning_capacity' not in inv
|
assert 'warning_capacity' not in inv
|
||||||
assert 'warning_offline' not in inv
|
assert 'warning_offline' not in inv
|
||||||
|
assert 'warning_deadends' not in inv
|
||||||
# Route array has single route with single element.
|
# Route array has single route with single element.
|
||||||
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
|
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
|
||||||
assert r['pubkey'] == l1.info['id']
|
assert r['pubkey'] == l1.info['id']
|
||||||
|
@ -206,6 +211,8 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
|
||||||
# If we explicitly say not to, it won't expose.
|
# If we explicitly say not to, it won't expose.
|
||||||
inv = l2.rpc.invoice(msatoshi=123456, label="inv1", description="?", exposeprivatechannels=False)
|
inv = l2.rpc.invoice(msatoshi=123456, label="inv1", description="?", exposeprivatechannels=False)
|
||||||
assert 'warning_capacity' in inv
|
assert 'warning_capacity' in inv
|
||||||
|
assert 'warning_offline' not in inv
|
||||||
|
assert 'warning_deadends' not in inv
|
||||||
assert 'routes' not in l1.rpc.decodepay(inv['bolt11'])
|
assert 'routes' not in l1.rpc.decodepay(inv['bolt11'])
|
||||||
|
|
||||||
# The existence of a public channel, even without capacity, will suppress
|
# The existence of a public channel, even without capacity, will suppress
|
||||||
|
@ -219,12 +226,15 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
|
||||||
wait_for(lambda: [c['public'] for c in l3.rpc.listchannels(scid)['channels']] == [True, True])
|
wait_for(lambda: [c['public'] for c in l3.rpc.listchannels(scid)['channels']] == [True, True])
|
||||||
|
|
||||||
inv = l2.rpc.invoice(msatoshi=10**7, label="inv2", description="?")
|
inv = l2.rpc.invoice(msatoshi=10**7, label="inv2", description="?")
|
||||||
assert 'warning_capacity' in inv
|
assert 'warning_deadends' in inv
|
||||||
|
assert 'warning_capacity' not in inv
|
||||||
|
assert 'warning_offline' not in inv
|
||||||
|
|
||||||
# Unless we tell it to include it.
|
# Unless we tell it to include it.
|
||||||
inv = l2.rpc.invoice(msatoshi=10**7, label="inv3", description="?", exposeprivatechannels=True)
|
inv = l2.rpc.invoice(msatoshi=10**7, label="inv3", description="?", exposeprivatechannels=True)
|
||||||
assert 'warning_capacity' not in inv
|
assert 'warning_capacity' not in inv
|
||||||
assert 'warning_offline' not in inv
|
assert 'warning_offline' not in inv
|
||||||
|
assert 'warning_deadends' not in inv
|
||||||
# Route array has single route with single element.
|
# Route array has single route with single element.
|
||||||
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
|
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
|
||||||
assert r['pubkey'] == l1.info['id']
|
assert r['pubkey'] == l1.info['id']
|
||||||
|
|
Loading…
Add table
Reference in a new issue