diff --git a/lightningd/channel.c b/lightningd/channel.c index caede53b9..fbf1f4ba8 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -17,6 +17,7 @@ #include #include #include +#include #include void channel_set_owner(struct channel *channel, struct subd *owner) @@ -601,20 +602,35 @@ struct channel_inflight *channel_inflight_find(struct channel *channel, } struct channel *any_channel_by_scid(struct lightningd *ld, - const struct short_channel_id *scid) + const struct short_channel_id *scid, + bool privacy_leak_ok) { struct peer *p; struct channel *chan; list_for_each(&ld->peers, p, list) { list_for_each(&p->channels, chan, list) { - if (chan->scid - && short_channel_id_eq(scid, chan->scid)) - return chan; - /* We also want to find the channel by its local alias - * when we forward. */ + /* BOLT-channel-type #2: + * - MUST always recognize the `alias` as a + * `short_channel_id` for incoming HTLCs to this + * channel. + */ if (chan->alias[LOCAL] && short_channel_id_eq(scid, chan->alias[LOCAL])) return chan; + /* BOLT-channel-type #2: + * - if `channel_type` has `option_scid_alias` set: + * - MUST NOT allow incoming HTLCs to this channel + * using the real `short_channel_id` + */ + /* FIXME: We don't keep type is db, so assume all + * private channels which support aliases want this! */ + if (!privacy_leak_ok + && chan->alias[REMOTE] + && !(chan->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL)) + continue; + if (chan->scid + && short_channel_id_eq(scid, chan->scid)) + return chan; } } return NULL; diff --git a/lightningd/channel.h b/lightningd/channel.h index 4e7f85d46..eba34ffa0 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -411,8 +411,11 @@ struct channel *peer_any_unsaved_channel(struct peer *peer, bool *others); struct channel *channel_by_dbid(struct lightningd *ld, const u64 dbid); +/* Includes both real scids and aliases. If !privacy_leak_ok, then private + * channels' real scids are not included. */ struct channel *any_channel_by_scid(struct lightningd *ld, - const struct short_channel_id *scid); + const struct short_channel_id *scid, + bool privacy_leak_ok); /* Get channel by channel_id */ struct channel *channel_by_cid(struct lightningd *ld, diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 0dfd9f32c..a240e11ac 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -123,7 +123,7 @@ static void handle_local_channel_update(struct lightningd *ld, const u8 *msg) /* In theory this could vanish before gossipd gets around to telling * us. */ - channel = any_channel_by_scid(ld, &scid); + channel = any_channel_by_scid(ld, &scid, true); if (!channel) { log_broken(ld->log, "Local update for bad scid %s", type_to_string(tmpctx, struct short_channel_id, diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 2b2365247..d13b53ff7 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -2027,7 +2027,7 @@ command_find_channel(struct command *cmd, tok->end - tok->start, buffer + tok->start); } else if (json_to_short_channel_id(buffer, tok, &scid)) { - *channel = any_channel_by_scid(ld, &scid); + *channel = any_channel_by_scid(ld, &scid, true); if (!*channel) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Short channel ID not found: '%.*s'", diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index db062591a..80d81745c 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -663,7 +663,7 @@ static void forward_htlc(struct htlc_in *hin, /* This is a shortcut for specifying next peer; doesn't mean * the actual channel! */ - next = any_channel_by_scid(ld, scid); + next = any_channel_by_scid(ld, scid, false); if (next) { struct peer *peer = next->peer; struct channel *channel; diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 915a2c55c..52308bedf 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -10,7 +10,8 @@ /* AUTOGENERATED MOCKS START */ /* Generated stub for any_channel_by_scid */ struct channel *any_channel_by_scid(struct lightningd *ld UNNEEDED, - const struct short_channel_id *scid UNNEEDED) + const struct short_channel_id *scid UNNEEDED, + bool privacy_leak_ok UNNEEDED) { fprintf(stderr, "any_channel_by_scid called!\n"); abort(); } /* Generated stub for bitcoind_getutxout_ */ void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED, diff --git a/tests/test_opening.py b/tests/test_opening.py index 1a078c66d..71da4a1f0 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1478,7 +1478,6 @@ def test_buy_liquidity_ad_no_v2(node_factory, bitcoind): compact_lease='029a002d000000004b2003e8') -@pytest.mark.xfail(strict=True, reason="We don't implement yet") def test_scid_alias_private(node_factory, bitcoind): """Test that we don't allow use of real scid for scid_alias-type channels""" l1, l2, l3 = node_factory.line_graph(3, fundchannel=False, opts=[{}, {}, diff --git a/tests/test_pay.py b/tests/test_pay.py index a35f2193f..7eabe1547 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -1857,7 +1857,7 @@ def test_pay_routeboost(node_factory, bitcoind): assert 'routehint_modifications' not in only_one(status['pay']) assert 'local_exclusions' not in only_one(status['pay']) attempts = only_one(status['pay'])['attempts'] - scid34 = only_one(l3.rpc.listpeers(l4.info['id'])['peers'])['channels'][0]['short_channel_id'] + scid34 = only_one(l3.rpc.listpeers(l4.info['id'])['peers'])['channels'][0]['alias']['local'] assert(len(attempts) == 1) a = attempts[0] assert(a['strategy'] == "Initial attempt") @@ -1866,7 +1866,7 @@ def test_pay_routeboost(node_factory, bitcoind): # With dev-route option we can test longer routehints. if DEVELOPER: - scid45 = only_one(l4.rpc.listpeers(l5.info['id'])['peers'])['channels'][0]['short_channel_id'] + scid45 = only_one(l4.rpc.listpeers(l5.info['id'])['peers'])['channels'][0]['alias']['local'] routel3l4l5 = [{'id': l3.info['id'], 'short_channel_id': scid34, 'fee_base_msat': 1000, @@ -3606,7 +3606,7 @@ def test_keysend_routehint(node_factory): routehints = [ [ { - 'scid': l3.rpc.listpeers()['peers'][0]['channels'][0]['short_channel_id'], + 'scid': l3.rpc.listpeers()['peers'][0]['channels'][0]['alias']['remote'], 'id': l2.info['id'], 'feebase': '1msat', 'feeprop': 10,