Skip to content

Commit 0e7615b

Browse files
committed
plugins/topology: remove local channels from listchannels.
Signed-off-by: Rusty Russell <[email protected]> Changelog-Removed: RPC `listchannels` no longer includes private local channels (deprecated v23.08, disabled by default in v24.11).
1 parent 73fc9b0 commit 0e7615b

File tree

3 files changed

+40
-182
lines changed

3 files changed

+40
-182
lines changed

doc/developers-guide/deprecations.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ hidden: false
1111
| rest-protocol.clnrest-prefix | Config | v23.11 | v24.11 | Autodetect where we need to rename `rest-protocol` to `clnrest-protocol` (added in v23.11) |
1212
| rest-host.clnrest-prefix | Config | v23.11 | v24.11 | Autodetect where we need to rename `rest-host` to `clnrest-host` (added in v23.11) |
1313
| rest-certs.clnrest-prefix | Config | v23.11 | v24.11 | Autodetect where we need to rename `rest-certs` to `clnrest-certs` (added in v23.11) |
14-
| listchannels.include_private | Field(s) | v24.02 | v24.08 | `listchannels` including private channels (now use listpeerchannels which gives far more detail) |
1514
| max-locktime-blocks | Config | v24.05 | v24.11 | --max-locktime-blocks is now set to 2016 in the BOLT 4 spec |
1615
| commando-rune | Command | v23.08 | v25.02 | replaced with `lightning-createrune` |
1716
| commando-listrunes | Command | v23.08 | v25.02 | replaced with `lightning-showrunes` |

plugins/topology.c

Lines changed: 39 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -200,22 +200,17 @@ static struct command_result *json_getroute(struct command *cmd,
200200
return send_outreq(req);
201201
}
202202

203-
HTABLE_DEFINE_NODUPS_TYPE(struct node_id, node_id_keyof, node_id_hash, node_id_eq,
204-
node_map);
205-
206203
/* To avoid multiple fetches, we represent directions as a bitmap
207204
* so we can do two at once. */
208205
static void json_add_halfchan(struct json_stream *response,
209206
struct gossmap *gossmap,
210-
const struct node_map *connected,
211207
const struct gossmap_chan *c,
212208
int dirbits)
213209
{
214210
struct short_channel_id scid;
215211
struct node_id node_id[2];
216212
const u8 *chanfeatures;
217213
struct amount_msat capacity_msat;
218-
bool local_disable;
219214

220215
/* These are channel (not per-direction) properties */
221216
chanfeatures = gossmap_chan_get_features(tmpctx, gossmap, c);
@@ -226,14 +221,6 @@ static void json_add_halfchan(struct json_stream *response,
226221

227222
capacity_msat = gossmap_chan_get_capacity(gossmap, c);
228223

229-
/* Deprecated: local channels are not "active" unless peer is connected. */
230-
if (connected && node_id_eq(&node_id[0], &local_id))
231-
local_disable = !node_map_get(connected, &node_id[1]);
232-
else if (connected && node_id_eq(&node_id[1], &local_id))
233-
local_disable = !node_map_get(connected, &node_id[0]);
234-
else
235-
local_disable = false;
236-
237224
for (int dir = 0; dir < 2; dir++) {
238225
u32 timestamp;
239226
u8 message_flags, channel_flags;
@@ -253,35 +240,21 @@ static void json_add_halfchan(struct json_stream *response,
253240
json_add_num(response, "direction", dir);
254241
json_add_bool(response, "public", !gossmap_chan_is_localmod(gossmap, c));
255242

256-
if (gossmap_chan_is_localmod(gossmap, c)) {
257-
/* Local additions don't have a channel_update
258-
* in gossmap. This is deprecated anyway, but
259-
* fill in values from entry we added. */
260-
timestamp = time_now().ts.tv_sec;
261-
message_flags = (ROUTING_OPT_HTLC_MAX_MSAT|ROUTING_OPT_DONT_FORWARD);
262-
channel_flags = node_id_idx(&node_id[dir], &node_id[!dir]);
263-
fee_base_msat = c->half[dir].base_fee;
264-
fee_proportional_millionths = c->half[dir].proportional_fee;
265-
htlc_minimum_msat = amount_msat(fp16_to_u64(c->half[dir].htlc_min));
266-
htlc_maximum_msat = amount_msat(fp16_to_u64(c->half[dir].htlc_max));
267-
} else {
268-
gossmap_chan_get_update_details(gossmap, c, dir,
269-
&timestamp,
270-
&message_flags,
271-
&channel_flags,
272-
NULL,
273-
&fee_base_msat,
274-
&fee_proportional_millionths,
275-
&htlc_minimum_msat,
276-
&htlc_maximum_msat);
277-
}
243+
gossmap_chan_get_update_details(gossmap, c, dir,
244+
&timestamp,
245+
&message_flags,
246+
&channel_flags,
247+
NULL,
248+
&fee_base_msat,
249+
&fee_proportional_millionths,
250+
&htlc_minimum_msat,
251+
&htlc_maximum_msat);
278252

279253
json_add_amount_msat(response, "amount_msat", capacity_msat);
280254
json_add_num(response, "message_flags", message_flags);
281255
json_add_num(response, "channel_flags", channel_flags);
282256

283-
json_add_bool(response, "active",
284-
c->half[dir].enabled && !local_disable);
257+
json_add_bool(response, "active", c->half[dir].enabled);
285258
json_add_num(response, "last_update", timestamp);
286259
json_add_num(response, "base_fee_millisatoshi", fee_base_msat);
287260
json_add_num(response, "fee_per_millionth",
@@ -296,188 +269,74 @@ static void json_add_halfchan(struct json_stream *response,
296269
}
297270
}
298271

299-
struct listchannels_opts {
272+
static struct command_result *json_listchannels(struct command *cmd,
273+
const char *buffer,
274+
const jsmntok_t *params)
275+
{
300276
struct node_id *source;
301277
struct node_id *destination;
302278
struct short_channel_id *scid;
303-
};
304-
305-
/* We record which local channels are valid; we could record which are
306-
* invalid, but our testsuite has some weirdness where it has local
307-
* channels in the store it knows nothing about. */
308-
static struct node_map *local_connected(const tal_t *ctx,
309-
const char *buf,
310-
const jsmntok_t *result)
311-
{
312-
size_t i;
313-
const jsmntok_t *channel, *channels = json_get_member(buf, result, "channels");
314-
struct node_map *connected = tal(ctx, struct node_map);
315-
316-
node_map_init(connected);
317-
tal_add_destructor(connected, node_map_clear);
318-
319-
json_for_each_arr(i, channel, channels) {
320-
struct node_id id;
321-
bool is_connected;
322-
const char *err, *state;
323-
324-
err = json_scan(tmpctx, buf, channel,
325-
"{peer_id:%,peer_connected:%,state:%}",
326-
JSON_SCAN(json_to_node_id, &id),
327-
JSON_SCAN(json_to_bool, &is_connected),
328-
JSON_SCAN_TAL(tmpctx, json_strdup, &state));
329-
if (err)
330-
plugin_err(plugin, "Bad listpeerchannels response (%s): %.*s",
331-
err,
332-
json_tok_full_len(result),
333-
json_tok_full(buf, result));
334-
335-
if (!is_connected)
336-
continue;
337-
338-
/* Must also have a channel in CHANNELD_NORMAL/splice */
339-
if (streq(state, "CHANNELD_NORMAL")
340-
|| streq(state, "CHANNELD_AWAITING_SPLICE")) {
341-
node_map_add(connected,
342-
tal_dup(connected, struct node_id, &id));
343-
}
344-
}
345-
346-
return connected;
347-
}
348-
349-
/* Only add a local entry if it's unknown publicly */
350-
static void gossmod_add_unknown_localchan(struct gossmap_localmods *mods,
351-
const struct node_id *self,
352-
const struct node_id *peer,
353-
const struct short_channel_id_dir *scidd,
354-
struct amount_msat capacity_msat,
355-
struct amount_msat min,
356-
struct amount_msat max,
357-
struct amount_msat spendable,
358-
struct amount_msat max_total_htlc,
359-
struct amount_msat fee_base,
360-
u32 fee_proportional,
361-
u16 cltv_delta,
362-
bool enabled,
363-
const char *buf UNUSED,
364-
const jsmntok_t *chantok UNUSED,
365-
struct gossmap *gossmap)
366-
{
367-
if (gossmap_find_chan(gossmap, &scidd->scid))
368-
return;
369-
370-
gossmod_add_localchan(mods, self, peer, scidd, capacity_msat,
371-
min, max, spendable, max_total_htlc,
372-
fee_base, fee_proportional, cltv_delta, enabled,
373-
buf, chantok, gossmap);
374-
}
375-
376-
static struct command_result *listpeerchannels_done(struct command *cmd,
377-
const char *method,
378-
const char *buf,
379-
const jsmntok_t *result,
380-
struct listchannels_opts *opts)
381-
{
382-
struct node_map *connected;
383279
struct gossmap_chan *c;
384280
struct json_stream *js;
385-
struct gossmap *gossmap = get_gossmap();
386-
struct gossmap_localmods *mods;
281+
struct gossmap *gossmap;
387282

388-
/* In deprecated mode, re-add private channels */
389-
if (command_deprecated_out_ok(cmd, "include_private", "v24.02", "v24.08")) {
390-
connected = local_connected(opts, buf, result);
391-
mods = gossmods_from_listpeerchannels(tmpctx, &local_id,
392-
buf, result, false,
393-
gossmod_add_unknown_localchan,
394-
gossmap);
395-
gossmap_apply_localmods(gossmap, mods);
396-
} else {
397-
connected = NULL;
398-
mods = NULL;
399-
}
283+
if (!param(cmd, buffer, params,
284+
p_opt("short_channel_id", param_short_channel_id,
285+
&scid),
286+
p_opt("source", param_node_id, &source),
287+
p_opt("destination", param_node_id, &destination),
288+
NULL))
289+
return command_param_failed();
290+
291+
if (!!scid + !!source + !!destination > 1)
292+
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
293+
"Can only specify one of "
294+
"`short_channel_id`, "
295+
"`source` or `destination`");
400296

297+
gossmap = get_gossmap();
401298
js = jsonrpc_stream_success(cmd);
402299
json_array_start(js, "channels");
403-
if (opts->scid) {
404-
c = gossmap_find_chan(gossmap, opts->scid);
300+
if (scid) {
301+
c = gossmap_find_chan(gossmap, scid);
405302
if (c)
406-
json_add_halfchan(js, gossmap, connected, c, 3);
407-
} else if (opts->source) {
303+
json_add_halfchan(js, gossmap, c, 3);
304+
} else if (source) {
408305
struct gossmap_node *src;
409306

410-
src = gossmap_find_node(gossmap, opts->source);
307+
src = gossmap_find_node(gossmap, source);
411308
if (src) {
412309
for (size_t i = 0; i < src->num_chans; i++) {
413310
int dir;
414311
c = gossmap_nth_chan(gossmap, src, i, &dir);
415-
json_add_halfchan(js, gossmap, connected,
312+
json_add_halfchan(js, gossmap,
416313
c, 1 << dir);
417314
}
418315
}
419-
} else if (opts->destination) {
316+
} else if (destination) {
420317
struct gossmap_node *dst;
421318

422-
dst = gossmap_find_node(gossmap, opts->destination);
319+
dst = gossmap_find_node(gossmap, destination);
423320
if (dst) {
424321
for (size_t i = 0; i < dst->num_chans; i++) {
425322
int dir;
426323
c = gossmap_nth_chan(gossmap, dst, i, &dir);
427-
json_add_halfchan(js, gossmap, connected,
324+
json_add_halfchan(js, gossmap,
428325
c, 1 << !dir);
429326
}
430327
}
431328
} else {
432329
for (c = gossmap_first_chan(gossmap);
433330
c;
434331
c = gossmap_next_chan(gossmap, c)) {
435-
json_add_halfchan(js, gossmap, connected, c, 3);
332+
json_add_halfchan(js, gossmap, c, 3);
436333
}
437334
}
438335

439336
json_array_end(js);
440-
441-
if (mods)
442-
gossmap_remove_localmods(gossmap, mods);
443-
444337
return command_finished(cmd, js);
445338
}
446339

447-
static struct command_result *json_listchannels(struct command *cmd,
448-
const char *buffer,
449-
const jsmntok_t *params)
450-
{
451-
struct listchannels_opts *opts = tal(cmd, struct listchannels_opts);
452-
struct out_req *req;
453-
454-
if (!param(cmd, buffer, params,
455-
p_opt("short_channel_id", param_short_channel_id,
456-
&opts->scid),
457-
p_opt("source", param_node_id, &opts->source),
458-
p_opt("destination", param_node_id, &opts->destination),
459-
NULL))
460-
return command_param_failed();
461-
462-
if (!!opts->scid + !!opts->source + !!opts->destination > 1)
463-
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
464-
"Can only specify one of "
465-
"`short_channel_id`, "
466-
"`source` or `destination`");
467-
468-
// FIXME: Once this deprecation is removed, `listpeerchannels_done` can
469-
// be embedded in the current function.
470-
if (command_deprecated_out_ok(cmd, "include_private", "v24.02", "v24.08")) {
471-
req = jsonrpc_request_start(cmd, "listpeerchannels",
472-
listpeerchannels_done, forward_error, opts);
473-
return send_outreq(req);
474-
}
475-
476-
// If deprecations are not necessary, call listpeerchannels_done directly,
477-
// the output will not be used there.
478-
return listpeerchannels_done(cmd, NULL, NULL, NULL, opts);
479-
}
480-
481340
static void json_add_node(struct json_stream *js,
482341
const struct gossmap *gossmap,
483342
const struct gossmap_node *n)

tests/test_plugin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1618,7 +1618,7 @@ def test_libplugin(node_factory):
16181618
myname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
16191619

16201620
# getmanifest assumes everyone handles string-based JSON ids:
1621-
l1.daemon.wait_for_log(r'test_libplugin: "[A-Za-z0-9:#]*/cln:getmanifest#[0-9]*"\[OUT\]')
1621+
l1.daemon.wait_for_log(r'test_libplugin: "[-A-Za-z0-9:#]*/cln:getmanifest#[0-9]*"\[OUT\]')
16221622

16231623
l1.daemon.wait_for_log("String name from datastore:.*object does not have member string")
16241624
l1.daemon.wait_for_log("Hex name from datastore: 00010203")

0 commit comments

Comments
 (0)