From 6112c99dbe032ee42462eb38442951f84a8ad7c9 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Mon, 23 Sep 2024 10:27:47 +0100 Subject: [PATCH] add askrene-disable-channel Changelog-EXPERIMENTAL: askrene: add askrene-disable-channel RPC Signed-off-by: Lagrang3 --- doc/Makefile | 1 + .../lightning-askrene-disable-channel.json | 57 +++++++++++++++++++ doc/schemas/lightning-askrene-listlayers.json | 22 +++++-- plugins/askrene/askrene.c | 42 ++++++++++++++ plugins/askrene/layer.c | 9 +++ plugins/askrene/layer.h | 4 ++ tests/test_askrene.py | 4 +- 7 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 doc/schemas/lightning-askrene-disable-channel.json diff --git a/doc/Makefile b/doc/Makefile index fd59c4182646..719b0527f2f7 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,6 +8,7 @@ GENERATE_MARKDOWN := doc/lightning-addgossip.7 \ doc/lightning-addpsbtoutput.7 \ doc/lightning-askrene-create-channel.7 \ doc/lightning-askrene-disable-node.7 \ + doc/lightning-askrene-disable-channel.7 \ doc/lightning-askrene-inform-channel.7 \ doc/lightning-askrene-listlayers.7 \ doc/lightning-askrene-reserve.7 \ diff --git a/doc/schemas/lightning-askrene-disable-channel.json b/doc/schemas/lightning-askrene-disable-channel.json new file mode 100644 index 000000000000..d791a8cd050e --- /dev/null +++ b/doc/schemas/lightning-askrene-disable-channel.json @@ -0,0 +1,57 @@ +{ + "$schema": "../rpc-schema-draft.json", + "type": "object", + "additionalProperties": false, + "rpc": "askrene-disable-channel", + "title": "Command to disable a channel in a layer (EXPERIMENTAL)", + "description": [ + "WARNING: experimental, so API may change.", + "", + "The **askrene-disable-channel** RPC command tells askrene to disable a channel whenever the given layer is used. This is mainly useful to force the use of alternate paths." + ], + "request": { + "required": [ + "layer", + "short_channel_id" + ], + "properties": { + "layer": { + "type": "string", + "description": [ + "The name of the layer to apply this change to." + ] + }, + "short_channel_id": { + "type": "short_channel_id", + "description": [ + "The channel to disable." + ] + }, + "direction": { + "type": "u32", + "description": [ + "The direction of the channel. If the direction is not specified then both directions are disabled." + ] + } + } + }, + "response": { + "required": [], + "properties": {} + }, + "see_also": [ + "lightning-getroutes(7)", + "lightning-askrene-create-channel(7)", + "lightning-askrene-inform-channel(7)", + "lightning-askrene-disable-node(7)", + "lightning-askrene-listlayers(7)", + "lightning-askrene-age(7)" + ], + "author": [ + "Rusty Russell <> is mainly responsible." + ], + "resources": [ + "Main web site: " + ] +} + diff --git a/doc/schemas/lightning-askrene-listlayers.json b/doc/schemas/lightning-askrene-listlayers.json index a0a5cba70511..a5531519f8d4 100644 --- a/doc/schemas/lightning-askrene-listlayers.json +++ b/doc/schemas/lightning-askrene-listlayers.json @@ -32,7 +32,7 @@ "additionalProperties": false, "required": [ "layer", - "disabled_nodes", + "disabled", "created_channels", "constraints" ], @@ -43,13 +43,23 @@ "The name of the layer." ] }, - "disabled_nodes": { + "disabled": { "type": "array", "items": { - "type": "pubkey", - "description": [ - "The id of the disabled node." - ] + "oneOf": [ + { + "type": "pubkey", + "description": [ + "The id of the disabled node." + ] + }, + { + "type": "short_channel_id_dir", + "description": [ + "The short channel id of the disabled channel." + ] + } + ] } }, "created_channels": { diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c index 751b687416ef..9cf17dd49e64 100644 --- a/plugins/askrene/askrene.c +++ b/plugins/askrene/askrene.c @@ -881,6 +881,44 @@ static struct command_result *json_askrene_inform_channel(struct command *cmd, return command_finished(cmd, response); } +static struct command_result *json_askrene_disable_channel(struct command *cmd, + const char *buffer, + const jsmntok_t *params) +{ + struct short_channel_id *scid; + int *direction; + const char *layername; + struct layer *layer; + struct json_stream *response; + struct askrene *askrene = get_askrene(cmd->plugin); + + if (!param(cmd, buffer, params, + p_req("layer", param_layername, &layername), + p_req("short_channel_id", param_short_channel_id, &scid), + p_opt("direction", param_zero_or_one, &direction), + NULL)) + return command_param_failed(); + + layer = find_layer(askrene, layername); + if (!layer) + layer = new_layer(askrene, layername); + + struct short_channel_id_dir scidd = {.scid = *scid}; + if (direction) { + scidd.dir = *direction; + layer_add_disabled_channel(layer, &scidd); + } else { + /* If no direction is provided we disable both. */ + scidd.dir = 0; + layer_add_disabled_channel(layer, &scidd); + scidd.dir = 1; + layer_add_disabled_channel(layer, &scidd); + } + + response = jsonrpc_stream_success(cmd); + return command_finished(cmd, response); +} + static struct command_result *json_askrene_disable_node(struct command *cmd, const char *buffer, const jsmntok_t *params) @@ -983,6 +1021,10 @@ static const struct plugin_command commands[] = { "askrene-age", json_askrene_age, }, + { + "askrene-disable-channel", + json_askrene_disable_channel, + }, }; static void askrene_markmem(struct plugin *plugin, struct htable *memtable) diff --git a/plugins/askrene/layer.c b/plugins/askrene/layer.c index 3636e79b9eb8..ae37b971c159 100644 --- a/plugins/askrene/layer.c +++ b/plugins/askrene/layer.c @@ -306,6 +306,15 @@ void layer_add_disabled_node(struct layer *layer, const struct node_id *node) tal_arr_expand(&layer->disabled, ex); } +void layer_add_disabled_channel(struct layer *layer, + const struct short_channel_id_dir *scidd) +{ + struct route_exclusion ex; + ex.type = EXCLUDE_CHANNEL; + ex.u.chan_id = *scidd; + tal_arr_expand(&layer->disabled, ex); +} + void layer_add_localmods(const struct layer *layer, const struct gossmap *gossmap, bool zero_cost, diff --git a/plugins/askrene/layer.h b/plugins/askrene/layer.h index 7acea220c072..5503644ae0c7 100644 --- a/plugins/askrene/layer.h +++ b/plugins/askrene/layer.h @@ -102,6 +102,10 @@ size_t layer_trim_constraints(struct layer *layer, u64 cutoff); /* Add a disabled node to a layer. */ void layer_add_disabled_node(struct layer *layer, const struct node_id *node); +/* Add a disabled channel to a layer. */ +void layer_add_disabled_channel(struct layer *layer, + const struct short_channel_id_dir *scidd); + /* Print out a json object per layer, or all if layer is NULL */ void json_add_layers(struct json_stream *js, struct askrene *askrene, diff --git a/tests/test_askrene.py b/tests/test_askrene.py index a87ae3c6ec53..9378e13b63ab 100644 --- a/tests/test_askrene.py +++ b/tests/test_askrene.py @@ -16,11 +16,11 @@ def test_layers(node_factory): assert l2.rpc.askrene_listlayers('test_layers') == {'layers': []} expect = {'layer': 'test_layers', - 'disabled_nodes': [], + 'disabled': [], 'created_channels': [], 'constraints': []} l2.rpc.askrene_disable_node('test_layers', l1.info['id']) - expect['disabled_nodes'].append(l1.info['id']) + expect['disabled'].append(l1.info['id']) assert l2.rpc.askrene_listlayers('test_layers') == {'layers': [expect]} assert l2.rpc.askrene_listlayers() == {'layers': [expect]} assert l2.rpc.askrene_listlayers('test_layers2') == {'layers': []}