Skip to content

Commit 741e947

Browse files
committed
askrene: add RPC askrene-query-reserve
Adds a new RPC to query the reserves on a given channel. It is necessary to know the total amount in-flight on a channel to be able to estimate the channel's liquidity after a failed routing attempt. Changelog-EXPERIMENTAL: askrene: add RPC askrene-query-reserve Signed-off-by: Lagrang3 <[email protected]>
1 parent 00e0b99 commit 741e947

File tree

6 files changed

+168
-0
lines changed

6 files changed

+168
-0
lines changed

doc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ GENERATE_MARKDOWN := doc/lightning-addgossip.7 \
1212
doc/lightning-askrene-listlayers.7 \
1313
doc/lightning-askrene-reserve.7 \
1414
doc/lightning-askrene-unreserve.7 \
15+
doc/lightning-askrene-query-reserve.7 \
1516
doc/lightning-autoclean-once.7 \
1617
doc/lightning-autoclean-status.7 \
1718
doc/lightning-batching.7 \
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"$schema": "../rpc-schema-draft.json",
3+
"type": "object",
4+
"additionalProperties": false,
5+
"rpc": "askrene-query-reserve",
6+
"title": "Command to query the reserved liquidity in a channel (EXPERIMENTAL)",
7+
"description": [
8+
"WARNING: experimental, so API may change.",
9+
"",
10+
"The **askrene-query-reserve** RPC command provides information about the number of in-flight HTLCs in a channel and the sum of their respective amounts."
11+
],
12+
"request": {
13+
"required": [
14+
"short_channel_id",
15+
"direction"
16+
],
17+
"properties": {
18+
"short_channel_id": {
19+
"type": "short_channel_id",
20+
"description": [
21+
"The short channel id of the channel."
22+
]
23+
},
24+
"direction": {
25+
"type": "u32",
26+
"description": [
27+
"The direction of the channel."
28+
]
29+
}
30+
}
31+
},
32+
"response": {
33+
"required": [
34+
"short_channel_id",
35+
"direction",
36+
"num_htlcs",
37+
"amount_msat"
38+
],
39+
"properties": {
40+
"short_channel_id": {
41+
"type": "short_channel_id",
42+
"description": [
43+
"The *short_channel_id* specified."
44+
]
45+
},
46+
"direction": {
47+
"type": "u32",
48+
"description": [
49+
"The *direction* specified."
50+
]
51+
},
52+
"num_htlcs": {
53+
"type": "u32",
54+
"description": [
55+
"The number of HTLCs in-flight in the channel."
56+
]
57+
},
58+
"amount_msat": {
59+
"type": "msat",
60+
"description": [
61+
"The total amount reserved in the channel."
62+
]
63+
}
64+
}
65+
},
66+
"see_also": [
67+
"lightning-getroutes(7)",
68+
"lightning-askrene-reserve(7)",
69+
"lightning-askrene-unreserve(7)",
70+
"lightning-askrene-inform-channel(7)",
71+
"lightning-askrene-disable-node(7)",
72+
"lightning-askrene-create-channel(7)",
73+
"lightning-askrene-listlayers(7)",
74+
"lightning-askrene-age(7)"
75+
],
76+
"author": [
77+
"Lagrang3 <<[email protected]>> is mainly responsible."
78+
],
79+
"resources": [
80+
"Main web site: <https://github.com/ElementsProject/lightning>"
81+
]
82+
}

doc/schemas/lightning-askrene-reserve.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"see_also": [
5858
"lightning-getroutes(7)",
5959
"lightning-askrene-unreserve(7)",
60+
"lightning-askrene-query-reserve(7)",
6061
"lightning-askrene-disable-node(7)",
6162
"lightning-askrene-create-channel(7)",
6263
"lightning-askrene-inform-channel(7)",

doc/schemas/lightning-askrene-unreserve.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"see_also": [
5858
"lightning-getroutes(7)",
5959
"lightning-askrene-reserve(7)",
60+
"lightning-askrene-query-reserve(7)",
6061
"lightning-askrene-disable-node(7)",
6162
"lightning-askrene-create-channel(7)",
6263
"lightning-askrene-inform-channel(7)",

plugins/askrene/askrene.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,39 @@ static struct command_result *json_askrene_unreserve(struct command *cmd,
761761
return command_finished(cmd, response);
762762
}
763763

764+
static struct command_result *
765+
json_askrene_query_reserve(struct command *cmd, const char *buffer,
766+
const jsmntok_t *params)
767+
{
768+
struct askrene *askrene = get_askrene(cmd->plugin);
769+
struct short_channel_id *scid;
770+
int *direction;
771+
struct short_channel_id_dir scidd;
772+
773+
if (!param(cmd, buffer, params,
774+
p_req("short_channel_id", param_short_channel_id, &scid),
775+
p_req("direction", param_zero_or_one, &direction), NULL))
776+
return command_param_failed();
777+
778+
scidd.scid = *scid;
779+
scidd.dir = *direction;
780+
781+
struct json_stream *response = jsonrpc_stream_success(cmd);
782+
json_add_short_channel_id(response, "short_channel_id", scidd.scid);
783+
json_add_num(response, "direction", scidd.dir);
784+
785+
const struct reserve *r = find_reserve(askrene->reserved, &scidd);
786+
if (!r) {
787+
json_add_u32(response, "num_htlcs", 0);
788+
json_add_amount_msat(response, "amount_msat", AMOUNT_MSAT(0));
789+
} else {
790+
791+
json_add_u32(response, "num_htlcs", r->num_htlcs);
792+
json_add_amount_msat(response, "amount_msat", r->amount);
793+
}
794+
return command_finished(cmd, response);
795+
}
796+
764797
static struct command_result *param_layername(struct command *cmd,
765798
const char *name,
766799
const char *buffer,
@@ -963,6 +996,10 @@ static const struct plugin_command commands[] = {
963996
"askrene-unreserve",
964997
json_askrene_unreserve,
965998
},
999+
{
1000+
"askrene-query-reserve",
1001+
json_askrene_query_reserve,
1002+
},
9661003
{
9671004
"askrene-disable-node",
9681005
json_askrene_disable_node,

tests/test_askrene.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,3 +677,49 @@ def test_min_htlc_after_excess(node_factory, bitcoind):
677677
layers=[],
678678
maxfee_msat=20_000_000,
679679
final_cltv=10)
680+
681+
682+
def test_reserve(node_factory):
683+
"""Test reserves"""
684+
# Set up l1 with this as the gossip_store
685+
l1 = node_factory.get_node()
686+
expected = {
687+
"short_channel_id": "1x1x1",
688+
"direction": 0,
689+
"num_htlcs": 0,
690+
"amount_msat": 0,
691+
}
692+
693+
assert l1.rpc.askrene_query_reserve("1x1x1", 0) == expected
694+
695+
l1.rpc.askrene_reserve(
696+
[{"short_channel_id": "1x1x1", "direction": 0, "amount_msat": 105}]
697+
)
698+
expected["num_htlcs"] += 1
699+
expected["amount_msat"] += 105
700+
701+
assert l1.rpc.askrene_query_reserve("1x1x1", 0) == expected
702+
703+
l1.rpc.askrene_reserve(
704+
[{"short_channel_id": "1x1x1", "direction": 0, "amount_msat": 900}]
705+
)
706+
expected["num_htlcs"] += 1
707+
expected["amount_msat"] += 900
708+
709+
assert l1.rpc.askrene_query_reserve("1x1x1", 0) == expected
710+
711+
l1.rpc.askrene_unreserve(
712+
[{"short_channel_id": "1x1x1", "direction": 0, "amount_msat": 105}]
713+
)
714+
expected["num_htlcs"] -= 1
715+
expected["amount_msat"] -= 105
716+
717+
assert l1.rpc.askrene_query_reserve("1x1x1", 0) == expected
718+
719+
l1.rpc.askrene_unreserve(
720+
[{"short_channel_id": "1x1x1", "direction": 0, "amount_msat": 900}]
721+
)
722+
expected["num_htlcs"] -= 1
723+
expected["amount_msat"] -= 900
724+
725+
assert l1.rpc.askrene_query_reserve("1x1x1", 0) == expected

0 commit comments

Comments
 (0)