lightnind: use aliases in routehints for private channels.

We *should* remember the channel type, since this is only required
if they set the channel_type to include option_scid_alias.

However, since we support channel upgrade, channel_type really needs
a new table.  I have a patch for that, from my abandoned original
"fastopen" branch for aliases, but it's too big a chance for rc2 IMHO.

Meanwhile, we allow exposeprivatechannels's scids to be either real or
the aliases.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Protocol: invoice routehints will use fake short-channel-ids for private channels if channel opened with option_scid_alias-supporting peer.
This commit is contained in:
Rusty Russell
2022-08-09 05:28:07 +09:30
committed by neil saitug
parent b479e9a9fa
commit cfe6b06fb5
4 changed files with 33 additions and 10 deletions

View File

@@ -54,7 +54,7 @@ If specified, *exposeprivatechannels* overrides the default route hint
logic, which will use unpublished channels only if there are no
published channels. If *true* unpublished channels are always considered
as a route hint candidate; if *false*, never. If it is a short channel id
(e.g. *1x1x3*) or array of short channel ids, only those specific channels
(e.g. *1x1x3*) or array of short channel ids (or a remote alias), only those specific channels
will be considered candidates, even if they are public or dead-ends.
The route hint is selected from the set of incoming channels of which:

View File

@@ -171,7 +171,10 @@ routehint_candidates(const tal_t *ctx,
/* Consider only hints they gave */
if (hints) {
log_debug(ld->log, "We have hints!");
if (!scid_in_arr(hints, &r->short_channel_id)) {
/* Allow specification by alias, too */
if (!scid_in_arr(hints, &r->short_channel_id)
&& (!candidate.c->alias[REMOTE]
|| !scid_in_arr(hints, candidate.c->alias[REMOTE]))) {
log_debug(ld->log, "scid %s not in hints",
type_to_string(tmpctx,
struct short_channel_id,
@@ -204,6 +207,22 @@ routehint_candidates(const tal_t *ctx,
continue;
}
/* BOLT-channel-type #2:
* - if `channel_type` has `option_scid_alias` set:
* - MUST NOT use the real `short_channel_id` in
* BOLT 11 `r` fields.
*/
/* FIXME: We don't remember the type explicitly, so
* we just assume all private channels negotiated since
* we had alias support want this. */
/* Note explicit flag test here: if we're told to expose all
* private channels, then "is_public" is forced true */
if (!(candidate.c->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL)
&& candidate.c->alias[REMOTE]) {
r->short_channel_id = *candidate.c->alias[REMOTE];
}
/* OK, finish it and append to one of the arrays. */
if (is_public) {
log_debug(ld->log, "%s: added to public",

View File

@@ -226,6 +226,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Make sure channel is totally public.
wait_for(lambda: [c['public'] for c in l2.rpc.listchannels(scid_dummy)['channels']] == [True, True])
alias = only_one(only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['channels'])['alias']['local']
# Since there's only one route, it will reluctantly hint that even
# though it's private
inv = l2.rpc.invoice(amount_msat=123456, label="inv0", description="?")
@@ -237,7 +238,9 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == l1.rpc.listchannels()['channels'][0]['short_channel_id']
# It uses our private alias!
assert r['short_channel_id'] != l1.rpc.listchannels()['channels'][0]['short_channel_id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6
@@ -261,7 +264,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == l1.rpc.listchannels()['channels'][0]['short_channel_id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6
@@ -276,7 +279,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == l1.rpc.listchannels()['channels'][0]['short_channel_id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6
@@ -308,7 +311,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == l1.rpc.listchannels()['channels'][0]['short_channel_id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6
@@ -322,7 +325,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == scid
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6
@@ -345,7 +348,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == scid
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6
@@ -365,7 +368,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == l1.rpc.listchannels()['channels'][0]['short_channel_id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
assert r['fee_proportional_millionths'] == 10
assert r['cltv_expiry_delta'] == 6

View File

@@ -5062,7 +5062,8 @@ gives a routehint straight to us causes an issue
inv = l3.rpc.invoice(10, "test", "test")['bolt11']
decoded = l3.rpc.decodepay(inv)
assert(only_one(only_one(decoded['routes']))['short_channel_id'] == scid23)
assert(only_one(only_one(decoded['routes']))['short_channel_id']
== only_one(only_one(l3.rpc.listpeers()['peers'])['channels'])['alias']['remote'])
l3.stop()
with pytest.raises(RpcError, match=r'Destination .* is not reachable directly and all routehints were unusable'):