From 046b402c184ae6c78beb9b61f7297e973d41e705 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 4 May 2020 09:49:32 +0930 Subject: [PATCH] gossipd: return channel_announcement features for listchannels. Signed-off-by: Rusty Russell Changelog-Added: JSON API: `listchannels` now shows channel `features`. --- gossipd/gossipd.c | 36 ++++++++++++++++++++++++++++++++++++ lightningd/gossip_control.c | 1 + lightningd/gossip_msg.c | 4 ++++ lightningd/gossip_msg.h | 1 + tests/test_gossip.py | 7 +++++-- tests/utils.py | 9 +++++++++ 6 files changed, 56 insertions(+), 2 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index c2d77373a..257c25a5d 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -966,6 +966,41 @@ static struct gossip_halfchannel_entry *hc_entry(const tal_t *ctx, return e; } +/*~ We don't keep channel features in memory; they're rarely used. So we + * remember if it exists, and load it off disk when needed. */ +static u8 *get_channel_features(const tal_t *ctx, + struct gossip_store *gs, + const struct chan *chan) +{ + secp256k1_ecdsa_signature sig; + u8 *features; + struct bitcoin_blkid chain_hash; + struct short_channel_id short_channel_id; + struct node_id node_id; + struct pubkey bitcoin_key; + struct amount_sat sats; + const u8 *ann; + + /* This is where we stash a flag to indicate it exists. */ + if (!chan->half[0].any_features) + return NULL; + + /* Could be a channel_announcement, could be a local_add_channel */ + ann = gossip_store_get(tmpctx, gs, chan->bcast.index); + if (!fromwire_channel_announcement(ctx, ann, &sig, &sig, &sig, &sig, + &features, &chain_hash, + &short_channel_id, + &node_id, &node_id, + &bitcoin_key, &bitcoin_key) + && !fromwire_gossipd_local_add_channel(ctx, ann, &short_channel_id, + &node_id, &sats, &features)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "bad channel_announcement / local_add_channel at %u: %s", + chan->bcast.index, tal_hex(tmpctx, ann)); + + return features; +} + /*~ Marshal (possibly) both channel directions into entries. */ static void append_channel(struct routing_state *rstate, const struct gossip_getchannels_entry ***entries, @@ -980,6 +1015,7 @@ static void append_channel(struct routing_state *rstate, e->local_disabled = is_chan_local_disabled(rstate, chan); e->public = is_chan_public(chan); e->short_channel_id = chan->scid; + e->features = get_channel_features(e, rstate->gs, chan); if (!srcfilter || node_id_eq(&e->node[0], srcfilter)) e->e[0] = hc_entry(*entries, chan, 0); else diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 946552336..4ed1b4bf5 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -482,6 +482,7 @@ static void json_add_halfchan(struct json_stream *response, json_add_num(response, "delay", he->delay); json_add_amount_msat_only(response, "htlc_minimum_msat", he->min); json_add_amount_msat_only(response, "htlc_maximum_msat", he->max); + json_add_hex_talarr(response, "features", e->features); json_object_end(response); } diff --git a/lightningd/gossip_msg.c b/lightningd/gossip_msg.c index 49bfb8c74..834236dfc 100644 --- a/lightningd/gossip_msg.c +++ b/lightningd/gossip_msg.c @@ -143,6 +143,8 @@ fromwire_gossip_getchannels_entry(const tal_t *ctx, fromwire_short_channel_id(pptr, max, &entry->short_channel_id); entry->public = fromwire_bool(pptr, max); entry->local_disabled = fromwire_bool(pptr, max); + entry->features = fromwire_tal_arrn(entry, + pptr, max, fromwire_u16(pptr, max)); if (fromwire_bool(pptr, max)) { entry->e[0] = tal(entry, struct gossip_halfchannel_entry); @@ -180,6 +182,8 @@ void towire_gossip_getchannels_entry(u8 **pptr, towire_short_channel_id(pptr, &entry->short_channel_id); towire_bool(pptr, entry->public); towire_bool(pptr, entry->local_disabled); + towire_u16(pptr, tal_bytelen(entry->features)); + towire_u8_array(pptr, entry->features, tal_bytelen(entry->features)); if (entry->e[0]) { towire_bool(pptr, true); towire_gossip_halfchannel_entry(pptr, entry->e[0]); diff --git a/lightningd/gossip_msg.h b/lightningd/gossip_msg.h index 1693b9748..5f4056192 100644 --- a/lightningd/gossip_msg.h +++ b/lightningd/gossip_msg.h @@ -33,6 +33,7 @@ struct gossip_getchannels_entry { bool local_disabled; /* NULL if we haven't received an update */ struct gossip_halfchannel_entry *e[2]; + u8 *features; }; struct gossip_getnodes_entry * diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 8e7187f9b..fee9d9f16 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1709,7 +1709,9 @@ def test_gossip_store_upgrade_v7_v8(node_factory): 'fee_per_millionth': 10, 'delay': 6, 'htlc_minimum_msat': Millisatoshi(0), - 'htlc_maximum_msat': Millisatoshi(990000000)}, + 'htlc_maximum_msat': Millisatoshi(990000000), + # This store was created on an experimental branch (OPT_ONION_MESSAGES) + 'features': '80000000000000000000000000'}, {'source': '0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518', 'destination': '022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59', 'short_channel_id': '103x1x1', @@ -1724,4 +1726,5 @@ def test_gossip_store_upgrade_v7_v8(node_factory): 'fee_per_millionth': 10, 'delay': 6, 'htlc_minimum_msat': Millisatoshi(0), - 'htlc_maximum_msat': Millisatoshi(990000000)}] + 'htlc_maximum_msat': Millisatoshi(990000000), + 'features': '80000000000000000000000000'}] diff --git a/tests/utils.py b/tests/utils.py index 814f05ded..80daf2c87 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -18,3 +18,12 @@ def expected_node_features(): """Return the expected node features hexstring for this configuration""" # features 1, 3, 7, 9, 11, 13, 15, 17 and 55 (0x8000000002aaa2). return "8000000002aaa2" + + +def expected_channel_features(): + """Return the expected channel features hexstring for this configuration""" + # experimental OPT_ONION_MESSAGES + if EXPERIMENTAL_FEATURES: + return '80000000000000000000000000' + else: + return ''