diff --git a/gossipd/gossip.c b/gossipd/gossip.c index 2f0cd98a5..f983a82e6 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -2104,6 +2104,8 @@ static struct io_plan *getchannels_req(struct io_conn *conn, struct daemon *daem static void append_node(const struct gossip_getnodes_entry ***nodes, const struct pubkey *nodeid, + const u8 *gfeatures, + const u8 *lfeatures, /* If non-NULL, contains more information */ const struct node *n) { @@ -2112,6 +2114,10 @@ static void append_node(const struct gossip_getnodes_entry ***nodes, new = tal(*nodes, struct gossip_getnodes_entry); new->nodeid = *nodeid; + new->global_features = tal_dup_arr(*nodes, u8, gfeatures, + tal_len(gfeatures), 0); + new->local_features = tal_dup_arr(*nodes, u8, lfeatures, + tal_len(lfeatures), 0); if (!n || n->last_timestamp < 0) { new->last_timestamp = -1; new->addresses = NULL; @@ -2140,13 +2146,15 @@ static struct io_plan *getnodes(struct io_conn *conn, struct daemon *daemon, for (size_t i = 0; i < tal_count(ids); i++) { n = get_node(daemon->rstate, &ids[i]); if (n) - append_node(&nodes, &ids[i], n); + /* FIXME: Keep global features from node_announcement! */ + append_node(&nodes, &ids[i], NULL, NULL, n); } } else { struct node_map_iter i; n = node_map_first(daemon->rstate->nodes, &i); while (n != NULL) { - append_node(&nodes, &n->id, n); + /* FIXME: Keep global features from node_announcement! */ + append_node(&nodes, &n->id, NULL, NULL, n); n = node_map_next(daemon->rstate->nodes, &i); } } @@ -3433,7 +3441,7 @@ static struct io_plan *get_peers(struct io_conn *conn, size_t n = 0; struct pubkey *id = tal_arr(conn, struct pubkey, n); struct wireaddr_internal *wireaddr = tal_arr(conn, struct wireaddr_internal, n); - const struct gossip_getnodes_entry **nodes = tal_arr(conn, const struct gossip_getnodes_entry *, 0); + const struct gossip_getnodes_entry **nodes = tal_arr(conn, const struct gossip_getnodes_entry *, n); struct pubkey *specific_id = NULL; if (!fromwire_gossip_getpeers_request(msg, msg, &specific_id)) @@ -3448,6 +3456,7 @@ static struct io_plan *get_peers(struct io_conn *conn, id[n] = peer->id; wireaddr[n] = peer->addr; append_node(&nodes, &peer->id, + peer->gfeatures, peer->lfeatures, get_node(daemon->rstate, &peer->id)); n++; } diff --git a/lightningd/gossip_msg.c b/lightningd/gossip_msg.c index e3ddd33ab..dc015a451 100644 --- a/lightningd/gossip_msg.c +++ b/lightningd/gossip_msg.c @@ -7,11 +7,19 @@ struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx, { u8 numaddresses, i; struct gossip_getnodes_entry *entry; + u16 flen; entry = tal(ctx, struct gossip_getnodes_entry); fromwire_pubkey(pptr, max, &entry->nodeid); - entry->last_timestamp = fromwire_u64(pptr, max); + flen = fromwire_u16(pptr, max); + entry->local_features = tal_arr(entry, u8, flen); + fromwire_u8_array(pptr, max, entry->local_features, flen); + flen = fromwire_u16(pptr, max); + entry->global_features = tal_arr(entry, u8, flen); + fromwire_u8_array(pptr, max, entry->global_features, flen); + + entry->last_timestamp = fromwire_u64(pptr, max); if (entry->last_timestamp < 0) { entry->addresses = NULL; entry->alias = NULL; @@ -30,6 +38,7 @@ struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx, entry->alias = tal_arr(entry, u8, fromwire_u8(pptr, max)); fromwire(pptr, max, entry->alias, tal_len(entry->alias)); fromwire(pptr, max, entry->color, sizeof(entry->color)); + return entry; } @@ -38,6 +47,12 @@ void towire_gossip_getnodes_entry(u8 **pptr, { u8 i, numaddresses = tal_count(entry->addresses); towire_pubkey(pptr, &entry->nodeid); + towire_u16(pptr, tal_count(entry->local_features)); + towire_u8_array(pptr, entry->local_features, + tal_count(entry->local_features)); + towire_u16(pptr, tal_count(entry->global_features)); + towire_u8_array(pptr, entry->global_features, + tal_count(entry->global_features)); towire_u64(pptr, entry->last_timestamp); if (entry->last_timestamp < 0) diff --git a/lightningd/gossip_msg.h b/lightningd/gossip_msg.h index d9b804118..5fe1b29f0 100644 --- a/lightningd/gossip_msg.h +++ b/lightningd/gossip_msg.h @@ -6,6 +6,8 @@ struct gossip_getnodes_entry { struct pubkey nodeid; + /* We'll only have non-empty local_features if it's a direct peer. */ + u8 *local_features, *global_features; s64 last_timestamp; /* -1 means never: following fields ignored */ struct wireaddr *addresses; u8 *alias; diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index f2d28ecb5..eb9f49ec9 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -708,6 +708,16 @@ static void json_add_node_decoration(struct json_result *response, { struct json_escaped *esc; + if (node->local_features) + json_add_hex(response, "local_features", + node->local_features, + tal_len(node->local_features)); + + if (node->global_features) + json_add_hex(response, "global_features", + node->global_features, + tal_len(node->global_features)); + /* If node announcement hasn't been received yet, no alias information. */ if (node->last_timestamp < 0) @@ -780,6 +790,7 @@ static void gossipd_getpeers_complete(struct subd *gossip, const u8 *msg, json_array_start(response, "channels"); json_add_uncommitted_channel(response, p->uncommitted_channel); + /* FIXME: Add their local and global features */ list_for_each(&p->channels, channel, list) { struct channel_id cid; u64 our_reserve_msat = channel->channel_info.their_config.channel_reserve_satoshis * 1000; diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index a78b6e98d..4f9c89108 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -426,6 +426,12 @@ class LightningDTests(BaseLightningDTests): .format(l1.daemon.lightning_dir, leaks)) l1.rpc.stop() + def test_features(self): + l1, l2 = self.connect() + + # LOCAL_INITIAL_ROUTING_SYNC + LOCAL_GOSSIP_QUERIES + assert l1.rpc.listpeers()['peers'][0]['local_features'] == '88' + def test_autocleaninvoice(self): l1 = self.node_factory.get_node()