From d745323f743c9caf74be9fe273af6bba26755661 Mon Sep 17 00:00:00 2001 From: ShahanaFarooqui Date: Thu, 14 Sep 2023 12:10:41 +0930 Subject: [PATCH] lightning/runes: added last_used in showrunes Changelog-Added: JSON-RPC: `showrunes` new field `last_used` --- doc/lightning-commando-listrunes.7.md | 3 ++- doc/lightning-showrunes.7.md | 3 ++- doc/schemas/commando-listrunes.schema.json | 5 +++++ doc/schemas/showrunes.schema.json | 5 +++++ lightningd/runes.c | 13 ++++++++++--- tests/test_runes.py | 20 ++++++++++++++++++++ 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/doc/lightning-commando-listrunes.7.md b/doc/lightning-commando-listrunes.7.md index 5e626a0b6..8f9c1fdba 100644 --- a/doc/lightning-commando-listrunes.7.md +++ b/doc/lightning-commando-listrunes.7.md @@ -31,6 +31,7 @@ On success, an object containing **runes** is returned. It is an array of objec - **restrictions\_as\_english** (string): English readable description of the restrictions array above - **stored** (boolean, optional): This is false if the rune does not appear in our datastore (only possible when `rune` is specified) (always *false*) - **blacklisted** (boolean, optional): The rune has been blacklisted; see commando-blacklist(7) (always *true*) +- **last\_used** (number, optional): The last time this rune was successfully used *(added 23.11)* - **our\_rune** (boolean, optional): This is not a rune for this node (only possible when `rune` is specified) (always *false*) [comment]: # (GENERATE-FROM-SCHEMA-END) @@ -50,4 +51,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:cd0e75bbeef3d5824448f67485de4679b0c163e97f405673b2ba9495f970d498) +[comment]: # ( SHA256STAMP:900e91777cd1e181c87a78913ab6f914585fcd99cd0dba16da19a81159f98aea) diff --git a/doc/lightning-showrunes.7.md b/doc/lightning-showrunes.7.md index fb7ce42b8..8128e0a84 100644 --- a/doc/lightning-showrunes.7.md +++ b/doc/lightning-showrunes.7.md @@ -29,6 +29,7 @@ On success, an object containing **runes** is returned. It is an array of objec - **restrictions\_as\_english** (string): English readable description of the restrictions array above - **stored** (boolean, optional): This is false if the rune does not appear in our datastore (only possible when `rune` is specified) (always *false*) - **blacklisted** (boolean, optional): The rune has been blacklisted; see commando-blacklist(7) (always *true*) +- **last\_used** (number, optional): The last time this rune was successfully used *(added 23.11)* - **our\_rune** (boolean, optional): This is not a rune for this node (only possible when `rune` is specified) (always *false*) [comment]: # (GENERATE-FROM-SCHEMA-END) @@ -48,4 +49,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:cd0e75bbeef3d5824448f67485de4679b0c163e97f405673b2ba9495f970d498) +[comment]: # ( SHA256STAMP:900e91777cd1e181c87a78913ab6f914585fcd99cd0dba16da19a81159f98aea) diff --git a/doc/schemas/commando-listrunes.schema.json b/doc/schemas/commando-listrunes.schema.json index c485d65b5..0fa759100 100644 --- a/doc/schemas/commando-listrunes.schema.json +++ b/doc/schemas/commando-listrunes.schema.json @@ -93,6 +93,11 @@ ], "description": "The rune has been blacklisted; see commando-blacklist(7)" }, + "last_used": { + "type": "number", + "description": "The last time this rune was successfully used", + "added": "23.11" + }, "our_rune": { "type": "boolean", "enum": [ diff --git a/doc/schemas/showrunes.schema.json b/doc/schemas/showrunes.schema.json index c485d65b5..0fa759100 100644 --- a/doc/schemas/showrunes.schema.json +++ b/doc/schemas/showrunes.schema.json @@ -93,6 +93,11 @@ ], "description": "The rune has been blacklisted; see commando-blacklist(7)" }, + "last_used": { + "type": "number", + "description": "The last time this rune was successfully used", + "added": "23.11" + }, "our_rune": { "type": "boolean", "enum": [ diff --git a/lightningd/runes.c b/lightningd/runes.c index 0c3cb8581..49d41769b 100644 --- a/lightningd/runes.c +++ b/lightningd/runes.c @@ -317,7 +317,8 @@ static struct command_result *json_add_rune(struct lightningd *ld, const char *fieldname, const char *runestr, const struct rune *rune, - bool stored) + bool stored, + struct timeabs last_used) { char *rune_english; rune_english = ""; @@ -332,6 +333,9 @@ static struct command_result *json_add_rune(struct lightningd *ld, if (rune_is_ours(ld, rune) != NULL) { json_add_bool(js, "our_rune", false); } + if (last_used.ts.tv_sec != 0) { + json_add_timeabs(js, "last_used", last_used); + } json_add_string(js, "unique_id", rune->unique_id); json_array_start(js, "restrictions"); for (size_t i = 0; i < tal_count(rune->restrs); i++) { @@ -377,15 +381,18 @@ static struct command_result *json_showrunes(struct command *cmd, struct timeabs last_used; const char *from_db = wallet_get_rune(tmpctx, cmd->ld->wallet, uid, &last_used); + /* This is how we indicate no timestamp: */ + if (!from_db) + last_used.ts.tv_sec = 0; /* We consider it stored iff this is exactly stored */ json_add_rune(cmd->ld, response, NULL, ras->runestr, ras->rune, - from_db && streq(from_db, ras->runestr)); + from_db && streq(from_db, ras->runestr), last_used); } else { struct timeabs *last_used; const char **strs = wallet_get_runes(cmd, cmd->ld->wallet, &last_used); for (size_t i = 0; i < tal_count(strs); i++) { const struct rune *r = rune_from_base64(cmd, strs[i]); - json_add_rune(cmd->ld, response, NULL, strs[i], r, true); + json_add_rune(cmd->ld, response, NULL, strs[i], r, true, last_used[i]); } } json_array_end(response); diff --git a/tests/test_runes.py b/tests/test_runes.py index fa18b6346..c9f733cbd 100644 --- a/tests/test_runes.py +++ b/tests/test_runes.py @@ -250,6 +250,26 @@ def test_showrunes(node_factory): assert not_our_rune['stored'] is False assert not_our_rune['our_rune'] is False + # test that we don't set timestamp if rune fails + new_rune = l1.rpc.createrune(restrictions=[["method=getinfo"]])['rune'] + assert "last_used" not in l1.rpc.showrunes(rune=new_rune)['runes'][0] + + with pytest.raises(RpcError, match='Not permitted:'): + l1.rpc.checkrune(nodeid=l1.info['id'], + rune=new_rune, + method='listchannels', + params={}) + assert "last_used" not in l1.rpc.showrunes(rune=new_rune)['runes'][0] + + before = time.time() + l1.rpc.checkrune(nodeid=l1.info['id'], + rune=new_rune, + method='getinfo', + params={}) + after = time.time() + + assert before <= l1.rpc.showrunes(rune=new_rune)['runes'][0]['last_used'] <= after + def test_blacklistrune(node_factory): l1 = node_factory.get_node()