From 9ab488fc41ea5f57efbd2eccfd58511755938549 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 30 Jan 2023 16:37:03 +1030 Subject: [PATCH] plugins/topology: add direction field to listchannels. It's a core concept in the spec which isn't directly exposed. Signed-off-by: Rusty Russell Changelog-Added: JSON-RPC: `listchannels` added a `direction` field (0 or 1) as per gossip specification. --- .msggen.json | 1 + cln-grpc/proto/node.proto | 1 + cln-grpc/src/convert.rs | 1 + cln-rpc/src/model.rs | 1 + contrib/pyln-testing/pyln/testing/grpc2py.py | 1 + doc/lightning-listchannels.7.md | 3 ++- doc/schemas/listchannels.schema.json | 5 +++++ plugins/topology.c | 1 + tests/test_gossip.py | 8 ++++++++ 9 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.msggen.json b/.msggen.json index 4bb7a19d7..1178f8385 100644 --- a/.msggen.json +++ b/.msggen.json @@ -545,6 +545,7 @@ "ListChannels.channels[].channel_flags": 7, "ListChannels.channels[].delay": 12, "ListChannels.channels[].destination": 2, + "ListChannels.channels[].direction": 16, "ListChannels.channels[].features": 15, "ListChannels.channels[].fee_per_millionth": 11, "ListChannels.channels[].htlc_maximum_msat": 14, diff --git a/cln-grpc/proto/node.proto b/cln-grpc/proto/node.proto index b7386cb25..c15e8c7f2 100644 --- a/cln-grpc/proto/node.proto +++ b/cln-grpc/proto/node.proto @@ -362,6 +362,7 @@ message ListchannelsChannels { bytes source = 1; bytes destination = 2; string short_channel_id = 3; + uint32 direction = 16; bool public = 4; Amount amount_msat = 5; uint32 message_flags = 6; diff --git a/cln-grpc/src/convert.rs b/cln-grpc/src/convert.rs index df5bb8e7d..9e8cd80a4 100644 --- a/cln-grpc/src/convert.rs +++ b/cln-grpc/src/convert.rs @@ -306,6 +306,7 @@ impl From for pb::ListchannelsChannels { source: c.source.serialize().to_vec(), // Rule #2 for type pubkey destination: c.destination.serialize().to_vec(), // Rule #2 for type pubkey short_channel_id: c.short_channel_id.to_string(), // Rule #2 for type short_channel_id + direction: c.direction, // Rule #2 for type u32 public: c.public, // Rule #2 for type boolean amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat message_flags: c.message_flags.into(), // Rule #2 for type u8 diff --git a/cln-rpc/src/model.rs b/cln-rpc/src/model.rs index 45ab1e82e..5be4b8e87 100644 --- a/cln-rpc/src/model.rs +++ b/cln-rpc/src/model.rs @@ -1869,6 +1869,7 @@ pub mod responses { pub source: PublicKey, pub destination: PublicKey, pub short_channel_id: ShortChannelId, + pub direction: u32, pub public: bool, pub amount_msat: Amount, pub message_flags: u8, diff --git a/contrib/pyln-testing/pyln/testing/grpc2py.py b/contrib/pyln-testing/pyln/testing/grpc2py.py index 5a4bdc1a3..3e8e2eb8f 100644 --- a/contrib/pyln-testing/pyln/testing/grpc2py.py +++ b/contrib/pyln-testing/pyln/testing/grpc2py.py @@ -258,6 +258,7 @@ def listchannels_channels2py(m): "source": hexlify(m.source), # PrimitiveField in generate_composite "destination": hexlify(m.destination), # PrimitiveField in generate_composite "short_channel_id": m.short_channel_id, # PrimitiveField in generate_composite + "direction": m.direction, # PrimitiveField in generate_composite "public": m.public, # PrimitiveField in generate_composite "amount_msat": amount2msat(m.amount_msat), # PrimitiveField in generate_composite "message_flags": m.message_flags, # PrimitiveField in generate_composite diff --git a/doc/lightning-listchannels.7.md b/doc/lightning-listchannels.7.md index 877fd440f..96e7cc7de 100644 --- a/doc/lightning-listchannels.7.md +++ b/doc/lightning-listchannels.7.md @@ -36,6 +36,7 @@ On success, an object containing **channels** is returned. It is an array of ob - **source** (pubkey): the source node - **destination** (pubkey): the destination node - **short\_channel\_id** (short\_channel\_id): short channel id of channel +- **direction** (u32): direction (0 if source < destination, 1 otherwise). - **public** (boolean): true if this is announced (otherwise it must be our channel) - **amount\_msat** (msat): the total capacity of this channel (always a whole number of satoshis) - **message\_flags** (u8): as defined by BOLT #7 @@ -79,4 +80,4 @@ Lightning RFC site - BOLT \#7: -[comment]: # ( SHA256STAMP:d8d52272963a9ec4708fd3ae41585ddd8120bb5444c03219a7b728f0b2e09ec3) +[comment]: # ( SHA256STAMP:78f59780528ae5cd33c3607ed11b128cc94e1e0a5e2babd59cb99574a3f5f956) diff --git a/doc/schemas/listchannels.schema.json b/doc/schemas/listchannels.schema.json index feea20285..acc083806 100644 --- a/doc/schemas/listchannels.schema.json +++ b/doc/schemas/listchannels.schema.json @@ -15,6 +15,7 @@ "source", "destination", "short_channel_id", + "direction", "public", "amount_msat", "message_flags", @@ -40,6 +41,10 @@ "type": "short_channel_id", "description": "short channel id of channel" }, + "direction": { + "type": "u32", + "description": "direction (0 if source < destination, 1 otherwise)." + }, "public": { "type": "boolean", "description": "true if this is announced (otherwise it must be our channel)" diff --git a/plugins/topology.c b/plugins/topology.c index 943dcd54d..a8e6017a7 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -244,6 +244,7 @@ static void json_add_halfchan(struct json_stream *response, json_add_node_id(response, "source", &node_id[dir]); json_add_node_id(response, "destination", &node_id[!dir]); json_add_short_channel_id(response, "short_channel_id", &scid); + json_add_num(response, "direction", dir); json_add_bool(response, "public", !c->private); gossmap_chan_get_update_details(gossmap, c, dir, diff --git a/tests/test_gossip.py b/tests/test_gossip.py index f4c5b52de..c7acc4481 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -425,6 +425,10 @@ def test_gossip_jsonrpc(node_factory): channels2 = l2.rpc.listchannels(source=l1.info['id'])['channels'] assert only_one(channels1)['source'] == l1.info['id'] assert only_one(channels1)['destination'] == l2.info['id'] + if l1.info['id'] > l2.info['id']: + assert only_one(channels1)['direction'] == 1 + else: + assert only_one(channels1)['direction'] == 0 assert channels1 == channels2 # Test listchannels-by-destination @@ -432,6 +436,10 @@ def test_gossip_jsonrpc(node_factory): channels2 = l2.rpc.listchannels(destination=l1.info['id'])['channels'] assert only_one(channels1)['destination'] == l1.info['id'] assert only_one(channels1)['source'] == l2.info['id'] + if l2.info['id'] > l1.info['id']: + assert only_one(channels1)['direction'] == 1 + else: + assert only_one(channels1)['direction'] == 0 assert channels1 == channels2 # Test only one of short_channel_id, source or destination can be supplied