Skip to content

Allow routing by older scids when we splice #8387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
146 changes: 107 additions & 39 deletions lightningd/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,75 @@ struct open_attempt *new_channel_open_attempt(struct channel *channel)
return oa;
}

static void chanmap_remove(struct lightningd *ld,
const struct channel *channel,
struct short_channel_id scid)
{
struct scid_to_channel *scc = channel_scid_map_get(ld->channels_by_scid, scid);
assert(scc->channel == channel);
tal_free(scc);
}

static void destroy_scid_to_channel(struct scid_to_channel *scc,
struct lightningd *ld)
{
if (!channel_scid_map_del(ld->channels_by_scid, scc))
abort();
}

static void chanmap_add(struct lightningd *ld,
struct channel *channel,
struct short_channel_id scid)
{
struct scid_to_channel *scc = tal(channel, struct scid_to_channel);
scc->channel = channel;
scc->scid = scid;
channel_scid_map_add(ld->channels_by_scid, scc);
tal_add_destructor2(scc, destroy_scid_to_channel, ld);
}

static void channel_set_random_local_alias(struct channel *channel)
{
assert(channel->alias[LOCAL] == NULL);
channel->alias[LOCAL] = tal(channel, struct short_channel_id);
randombytes_buf(channel->alias[LOCAL], sizeof(struct short_channel_id));
/* We don't check for uniqueness. We would crash on a clash, but your machine is
* probably broken beyond repair if it gets two equal 64 bit numbers */
chanmap_add(channel->peer->ld, channel, *channel->alias[LOCAL]);
}

void channel_set_scid(struct channel *channel, const struct short_channel_id *new_scid)
{
struct lightningd *ld = channel->peer->ld;

/* Get rid of old one (if any) */
if (channel->scid != NULL) {
chanmap_remove(ld, channel, *channel->scid);
channel->scid = tal_free(channel->scid);
}

/* Add new one (if any) */
if (new_scid) {
channel->scid = tal_dup(channel, struct short_channel_id, new_scid);
chanmap_add(ld, channel, *new_scid);
}
}

void channel_add_old_scid(struct channel *channel,
struct short_channel_id old_scid)
{
/* If this is not public, we skip */
if (!(channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL))
return;

if (!channel->old_scids)
channel->old_scids = tal_dup(channel, struct short_channel_id, &old_scid);
else
tal_arr_expand(&channel->old_scids, old_scid);

chanmap_add(channel->peer->ld, channel, old_scid);
}

struct channel *new_unsaved_channel(struct peer *peer,
u32 feerate_base,
u32 feerate_ppm)
Expand Down Expand Up @@ -275,6 +344,7 @@ struct channel *new_unsaved_channel(struct peer *peer,
channel->last_htlc_sigs = NULL;
channel->remote_channel_ready = false;
channel->scid = NULL;
channel->old_scids = NULL;
channel->next_index[LOCAL] = 1;
channel->next_index[REMOTE] = 1;
channel->next_htlc_id = 0;
Expand All @@ -286,10 +356,8 @@ struct channel *new_unsaved_channel(struct peer *peer,
= CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
channel->shutdown_wrong_funding = NULL;
channel->closing_feerate_range = NULL;
channel->alias[REMOTE] = NULL;
/* We don't even bother checking for clashes. */
channel->alias[LOCAL] = tal(channel, struct short_channel_id);
randombytes_buf(channel->alias[LOCAL], sizeof(struct short_channel_id));
channel->alias[REMOTE] = channel->alias[LOCAL] = NULL;
channel_set_random_local_alias(channel);

channel->shutdown_scriptpubkey[REMOTE] = NULL;
channel->last_was_revoke = false;
Expand Down Expand Up @@ -411,6 +479,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
bool remote_channel_ready,
/* NULL or stolen */
struct short_channel_id *scid,
struct short_channel_id *old_scids TAKES,
struct short_channel_id *alias_local TAKES,
struct short_channel_id *alias_remote STEALS,
struct channel_id *cid,
Expand Down Expand Up @@ -538,12 +607,20 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
channel->our_funds = our_funds;
channel->remote_channel_ready = remote_channel_ready;
channel->scid = tal_steal(channel, scid);
channel->old_scids = tal_dup_talarr(channel, struct short_channel_id, old_scids);
channel->alias[LOCAL] = tal_dup_or_null(channel, struct short_channel_id, alias_local);
/* All these possible short_channel_id variants go in the lookup table! */
if (channel->scid)
chanmap_add(peer->ld, channel, *channel->scid);
if (channel->alias[LOCAL])
chanmap_add(peer->ld, channel, *channel->alias[LOCAL]);
for (size_t i = 0; i < tal_count(channel->old_scids); i++)
chanmap_add(peer->ld, channel, channel->old_scids[i]);

/* We always make sure this is set (historical channels from db might not) */
if (!channel->alias[LOCAL]) {
channel->alias[LOCAL] = tal(channel, struct short_channel_id);
randombytes_buf(channel->alias[LOCAL], sizeof(struct short_channel_id));
}
if (!channel->alias[LOCAL])
channel_set_random_local_alias(channel);

channel->alias[REMOTE] = tal_steal(channel, alias_remote); /* Haven't gotten one yet. */
channel->cid = *cid;
channel->our_msat = our_msat;
Expand Down Expand Up @@ -737,37 +814,28 @@ struct channel *any_channel_by_scid(struct lightningd *ld,
struct short_channel_id scid,
bool privacy_leak_ok)
{
struct peer *p;
struct channel *chan;
struct peer_node_id_map_iter it;

/* FIXME: Support lookup by scid directly! */
for (p = peer_node_id_map_first(ld->peers, &it);
p;
p = peer_node_id_map_next(ld->peers, &it)) {
list_for_each(&p->channels, chan, list) {
/* BOLT #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 #2:
* - if `channel_type` has `option_scid_alias` set:
* - MUST NOT allow incoming HTLCs to this channel
* using the real `short_channel_id`
*/
if (!privacy_leak_ok
&& channel_type_has(chan->type, OPT_SCID_ALIAS))
continue;
if (chan->scid
&& short_channel_id_eq(scid, *chan->scid))
return chan;
}
}
return NULL;
const struct scid_to_channel *scc = channel_scid_map_get(ld->channels_by_scid, scid);
if (!scc)
return NULL;

/* BOLT #2:
* - MUST always recognize the `alias` as a `short_channel_id` for
* incoming HTLCs to this channel.
*/
if (scc->channel->alias[LOCAL]
&& short_channel_id_eq(scid, *scc->channel->alias[LOCAL]))
return scc->channel;

/* BOLT #2:
* - if `channel_type` has `option_scid_alias` set:
* - MUST NOT allow incoming HTLCs to this channel using the real
* `short_channel_id`
*/
/* This means any scids other than the alias (handled above) cannot be exposed */
if (!privacy_leak_ok && channel_type_has(scc->channel->type, OPT_SCID_ALIAS))
return NULL;

return scc->channel;
}

struct channel *channel_by_dbid(struct lightningd *ld, const u64 dbid)
Expand Down
37 changes: 37 additions & 0 deletions lightningd/channel.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_H
#define LIGHTNING_LIGHTNINGD_CHANNEL_H
#include "config.h"
#include <ccan/htable/htable_type.h>
#include <common/channel_config.h>
#include <common/channel_id.h>
#include <common/channel_type.h>
Expand Down Expand Up @@ -214,6 +215,8 @@ struct channel {
bool remote_channel_ready;
/* Channel if locked locally. */
struct short_channel_id *scid;
/* Old scids if we were spliced */
struct short_channel_id *old_scids;

/* Alias used for option_zeroconf, or option_scid_alias, if
* present. LOCAL are all the alias we told the peer about and
Expand Down Expand Up @@ -388,6 +391,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
bool remote_channel_ready,
/* NULL or stolen */
struct short_channel_id *scid STEALS,
struct short_channel_id *old_scids TAKES,
struct short_channel_id *alias_local STEALS,
struct short_channel_id *alias_remote STEALS,
struct channel_id *cid,
Expand Down Expand Up @@ -487,6 +491,10 @@ u32 channel_last_funding_feerate(const struct channel *channel);
/* Only set completely_eliminate for never-existed channels */
void delete_channel(struct channel *channel STEALS, bool completely_eliminate);

/* Add a historic (public) short_channel_id to this channel */
void channel_add_old_scid(struct channel *channel,
struct short_channel_id old_scid);

const char *channel_state_name(const struct channel *channel);
const char *channel_state_str(enum channel_state state);

Expand Down Expand Up @@ -833,6 +841,35 @@ struct channel *peer_any_channel_bystate(struct peer *peer,

struct channel *channel_by_dbid(struct lightningd *ld, const u64 dbid);

struct scid_to_channel {
struct short_channel_id scid;
struct channel *channel;
};

static inline const struct short_channel_id scid_to_channel_key(const struct scid_to_channel *scidchan)
{
return scidchan->scid;
}

static inline bool scid_to_channel_eq_scid(const struct scid_to_channel *scidchan,
struct short_channel_id scid)
{
return short_channel_id_eq(scidchan->scid, scid);
}

/* Define channel_scid_map */
HTABLE_DEFINE_NODUPS_TYPE(struct scid_to_channel,
scid_to_channel_key,
short_channel_id_hash,
scid_to_channel_eq_scid,
channel_scid_map);

/* The only allowed way to set channel->scid */
void channel_set_scid(struct channel *channel, const struct short_channel_id *new_scid);

/* The only allowed way to set channel->alias[LOCAL] */
void channel_set_local_alias(struct channel *channel, struct short_channel_id alias_scid);

/* 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,
Expand Down
8 changes: 6 additions & 2 deletions lightningd/channel_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ bool depthcb_update_scid(struct channel *channel,
if (!channel->scid) {
wallet_annotate_txout(ld->wallet, outpoint,
TX_CHANNEL_FUNDING, channel->dbid);
channel->scid = tal_dup(channel, struct short_channel_id, &scid);
channel_set_scid(channel, &scid);

/* If we have a zeroconf channel, i.e., no scid yet
* but have exchange `channel_ready` messages, then we
Expand All @@ -815,12 +815,16 @@ bool depthcb_update_scid(struct channel *channel,
lockin_has_completed(channel, false);

} else {
struct short_channel_id old_scid = *channel->scid;

/* We freaked out if required when original was
* removed, so just update now */
log_info(channel->log, "Short channel id changed from %s->%s",
fmt_short_channel_id(tmpctx, *channel->scid),
fmt_short_channel_id(tmpctx, scid));
*channel->scid = scid;
channel_set_scid(channel, &scid);
/* In case we broadcast it before (e.g. splice!) */
channel_add_old_scid(channel, old_scid);
channel_gossip_scid_changed(channel);
}

Expand Down
4 changes: 2 additions & 2 deletions lightningd/dual_open_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,15 +1038,15 @@ static enum watch_result opening_depth_cb(struct lightningd *ld,
if (!inflight->channel->scid) {
wallet_annotate_txout(ld->wallet, &inflight->funding->outpoint,
TX_CHANNEL_FUNDING, inflight->channel->dbid);
inflight->channel->scid = tal_dup(inflight->channel, struct short_channel_id, &scid);
channel_set_scid(inflight->channel, &scid);
wallet_channel_save(ld->wallet, inflight->channel);
} else if (!short_channel_id_eq(*inflight->channel->scid, scid)) {
/* We freaked out if required when original was
* removed, so just update now */
log_info(inflight->channel->log, "Short channel id changed from %s->%s",
fmt_short_channel_id(tmpctx, *inflight->channel->scid),
fmt_short_channel_id(tmpctx, scid));
*inflight->channel->scid = scid;
channel_set_scid(inflight->channel, &scid);
wallet_channel_save(ld->wallet, inflight->channel);
}

Expand Down
4 changes: 4 additions & 0 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
ld->peers_by_dbid = tal(ld, struct peer_dbid_map);
peer_dbid_map_init(ld->peers_by_dbid);

/*~ This speeds lookups for short_channel_ids to their channels. */
ld->channels_by_scid = tal(ld, struct channel_scid_map);
channel_scid_map_init(ld->channels_by_scid);

/*~ For multi-part payments, we need to keep some incoming payments
* in limbo until we get all the parts, or we time them out. */
ld->htlc_sets = tal(ld, struct htlc_set_map);
Expand Down
2 changes: 2 additions & 0 deletions lightningd/lightningd.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ struct lightningd {
struct peer_node_id_map *peers;
/* And those in database by dbid */
struct peer_dbid_map *peers_by_dbid;
/* Here are all our channels and their aliases */
struct channel_scid_map *channels_by_scid;

/* Outstanding connect commands. */
struct list_head connects;
Expand Down
2 changes: 2 additions & 0 deletions lightningd/memdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <gossipd/gossipd_wiregen.h>
#include <hsmd/hsmd_wiregen.h>
#include <lightningd/chaintopology.h>
#include <lightningd/channel.h>
#include <lightningd/closed_channel.h>
#include <lightningd/hsm_control.h>
#include <lightningd/jsonrpc.h>
Expand Down Expand Up @@ -202,6 +203,7 @@ static bool lightningd_check_leaks(struct command *cmd)
memleak_scan_htable(memtable, &ld->htlc_sets->raw);
memleak_scan_htable(memtable, &ld->peers->raw);
memleak_scan_htable(memtable, &ld->peers_by_dbid->raw);
memleak_scan_htable(memtable, &ld->channels_by_scid->raw);
memleak_scan_htable(memtable, &ld->closed_channels->raw);
wallet_memleak_scan(memtable, ld->wallet);

Expand Down
2 changes: 2 additions & 0 deletions lightningd/opening_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ wallet_commit_channel(struct lightningd *ld,
local_funding,
false, /* !remote_channel_ready */
NULL, /* no scid yet */
NULL, /* no old scids */
NULL, /* assign random local alias */
NULL, /* They haven't told us an alias yet */
cid,
Expand Down Expand Up @@ -1579,6 +1580,7 @@ static struct channel *stub_chan(struct command *cmd,
AMOUNT_SAT(0),
true, /* remote_channel_ready */
scid,
NULL,
scid,
scid,
&cid,
Expand Down
2 changes: 1 addition & 1 deletion lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -2225,7 +2225,7 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
/* That's not entirely unexpected in early states */
log_debug(channel->log, "Funding tx %s reorganized out!",
fmt_bitcoin_txid(tmpctx, txid));
channel->scid = tal_free(channel->scid);
channel_set_scid(channel, NULL);
return KEEP_WATCHING;

/* But it's often Bad News in later states */
Expand Down
Loading
Loading