Skip to content

Commit

Permalink
add askrene-disable-channel
Browse files Browse the repository at this point in the history
Changelog-EXPERIMENTAL: askrene: add askrene-disable-channel RPC

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
  • Loading branch information
Lagrang3 authored and ShahanaFarooqui committed Sep 25, 2024
1 parent 6f087dd commit d4cb5b8
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 13 deletions.
76 changes: 71 additions & 5 deletions contrib/msggen/msggen/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,62 @@
"Main web site: <https://github.com/ElementsProject/lightning>"
]
},
"lightning-askrene-disable-channel.json": {
"$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 <<rusty@rustcorp.com.au>> is mainly responsible."
],
"resources": [
"Main web site: <https://github.com/ElementsProject/lightning>"
]
},
"lightning-askrene-disable-node.json": {
"$schema": "../rpc-schema-draft.json",
"type": "object",
Expand Down Expand Up @@ -555,7 +611,7 @@
"additionalProperties": false,
"required": [
"layer",
"disabled_nodes",
"disabled",
"created_channels",
"constraints"
],
Expand All @@ -566,12 +622,22 @@
"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."
]
}
]
}
},
Expand Down
1 change: 1 addition & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Core Lightning Documentation
lightning-addgossip <lightning-addgossip.7.md>
lightning-addpsbtoutput <lightning-addpsbtoutput.7.md>
lightning-askrene-create-channel <lightning-askrene-create-channel.7.md>
lightning-askrene-disable-channel <lightning-askrene-disable-channel.7.md>
lightning-askrene-disable-node <lightning-askrene-disable-node.7.md>
lightning-askrene-inform-channel <lightning-askrene-inform-channel.7.md>
lightning-askrene-listlayers <lightning-askrene-listlayers.7.md>
Expand Down
57 changes: 57 additions & 0 deletions doc/schemas/lightning-askrene-disable-channel.json
Original file line number Diff line number Diff line change
@@ -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 <<rusty@rustcorp.com.au>> is mainly responsible."
],
"resources": [
"Main web site: <https://github.com/ElementsProject/lightning>"
]
}

22 changes: 16 additions & 6 deletions doc/schemas/lightning-askrene-listlayers.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"additionalProperties": false,
"required": [
"layer",
"disabled_nodes",
"disabled",
"created_channels",
"constraints"
],
Expand All @@ -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": {
Expand Down
42 changes: 42 additions & 0 deletions plugins/askrene/askrene.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions plugins/askrene/layer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions plugins/askrene/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 17 additions & 2 deletions tests/test_askrene.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ 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': []}

l2.rpc.askrene_disable_channel('test_layers', "1x2x3", 0)
expect['disabled'].append("1x2x3/0")
assert l2.rpc.askrene_listlayers('test_layers') == {'layers': [expect]}

# Tell it l3 connects to l1!
l2.rpc.askrene_create_channel('test_layers',
l3.info['id'],
Expand Down Expand Up @@ -164,6 +168,17 @@ def test_getroutes(node_factory):
# Set up l1 with this as the gossip_store
l1 = node_factory.get_node(gossip_store_file=gsfile.name)

# Disabling channels makes getroutes fail
l1.rpc.askrene_disable_channel("chans_disabled", "0x1x0")
l1.rpc.askrene_disable_channel("chans_disabled", "0x2x1")
l1.rpc.askrene_disable_channel("chans_disabled", "0x2x3")
with pytest.raises(RpcError, match="Could not find route"):
l1.rpc.getroutes(source=nodemap[0],
destination=nodemap[1],
amount_msat=1000,
layers=["chans_disabled"],
maxfee_msat=1000,
final_cltv=99)
# Start easy
assert l1.rpc.getroutes(source=nodemap[0],
destination=nodemap[1],
Expand Down

0 comments on commit d4cb5b8

Please sign in to comment.